Merge branch 'master' into recommended

Conflicts:
	media/css/reader.css
This commit is contained in:
Samuel Clay 2011-03-11 19:53:45 -05:00
commit a3e974f329
46 changed files with 11354 additions and 230 deletions

View file

@ -9,7 +9,16 @@ from lxml import etree
from utils import json_functions as json, urlnorm
import utils.opml as opml
from utils import log as logging
from xml.etree.ElementTree import Element, SubElement, Comment, tostring
# import minidom
# def prettify(elem):
# """Return a pretty-printed XML string for the Element.
# """
# rough_string = ElementTree.tostring(elem, 'utf-8')
# reparsed = minidom.parseString(rough_string)
# return reparsed.toprettyxml(indent=" ")
class OAuthToken(models.Model):
user = models.OneToOneField(User, null=True, blank=True)
session_id = models.CharField(max_length=50, null=True, blank=True)
@ -20,6 +29,64 @@ class OAuthToken(models.Model):
access_token_secret = models.CharField(max_length=50)
created_date = models.DateTimeField(default=datetime.datetime.now)
class OPMLExporter:
def __init__(self, user):
self.user = user
self.fetch_feeds()
def process(self):
now = str(datetime.datetime.now())
root = Element('opml')
root.set('version', '1.1')
root.append(Comment('Generated by NewsBlur - www.newsblur.com'))
head = SubElement(root, 'head')
title = SubElement(head, 'title')
title.text = 'NewsBlur Feeds'
dc = SubElement(head, 'dateCreated')
dc.text = now
dm = SubElement(head, 'dateModified')
dm.text = now
folders = self.get_folders()
body = SubElement(root, 'body')
self.process_outline(body, folders)
return tostring(root)
def process_outline(self, body, folders):
for obj in folders:
if isinstance(obj, int):
feed = self.feeds[obj]
feed_attrs = self.make_feed_row(feed)
body.append(Element('outline', feed_attrs))
elif isinstance(obj, dict):
print obj
for folder_title, folder_objs in obj.items():
folder_element = Element('outline', {'text': folder_title, 'title': folder_title})
body.append(self.process_outline(folder_element, folder_objs))
return body
def make_feed_row(self, feed):
feed_attrs = {
'text': feed['feed_title'],
'title': feed['feed_title'],
'type': 'rss',
'version': 'RSS',
'htmlUrl': feed['feed_link'],
'xmlUrl': feed['feed_address'],
}
return feed_attrs
def get_folders(self):
folders = UserSubscriptionFolders.objects.get(user=self.user)
return json.decode(folders.folders)
def fetch_feeds(self):
subs = UserSubscription.objects.filter(user=self.user)
self.feeds = dict((sub.feed.pk, sub.canonical()) for sub in subs)
class Importer:

View file

@ -3,6 +3,7 @@ from apps.feed_import import views
urlpatterns = patterns('apps.feed_import.views',
url(r'^opml_upload$', views.opml_upload, name='opml-upload'),
url(r'^opml_export$', views.opml_export, name='opml-export'),
url(r'^authorize/$', views.reader_authorize, name='google-reader-authorize'),
url(r'^callback/$', views.reader_callback, name='google-reader-callback'),
url(r'^signup/$', views.import_signup, name='import-signup'),

View file

@ -1,3 +1,4 @@
import datetime
import urlparse
from utils import log as logging
import oauth2 as oauth
@ -11,7 +12,7 @@ from django.contrib.auth import login as login_user
from django.shortcuts import render_to_response
from apps.reader.forms import SignupForm
from apps.reader.models import UserSubscription
from apps.feed_import.models import OAuthToken, OPMLImporter, GoogleReaderImporter
from apps.feed_import.models import OAuthToken, OPMLImporter, OPMLExporter, GoogleReaderImporter
from utils import json_functions as json
from utils.user_functions import ajax_login_required
@ -43,6 +44,18 @@ def opml_upload(request):
data = json.encode(dict(message=message, code=code, payload=payload))
return HttpResponse(data, mimetype='text/plain')
@ajax_login_required
def opml_export(request):
exporter = OPMLExporter(request.user)
opml = exporter.process()
now = datetime.datetime.now()
response = HttpResponse(opml, mimetype='text/xml')
response['Content-Disposition'] = 'attachment; filename=NewsBlur Subscriptions - %s' % (
now.strftime('%d %B %Y')
)
return response
def reader_authorize(request):
logging.user(request.user, "~BB~FW~SBAuthorize Google Reader import - %s" % (

View file

@ -226,9 +226,13 @@ def load_feeds_iphone(request):
@json.json_view
def refresh_feeds(request):
start = datetime.datetime.utcnow()
user = get_user(request)
feed_ids = request.REQUEST.getlist('feed_id')
feeds = {}
user_subs = UserSubscription.objects.select_related('feed').filter(user=user, active=True)
if feed_ids:
user_subs = user_subs.filter(feed__in=feed_ids)
UNREAD_CUTOFF = datetime.datetime.utcnow() - datetime.timedelta(days=settings.DAYS_OF_UNREAD)
favicons_fetching = [int(f) for f in request.POST.getlist('favicons_fetching') if f]
@ -254,10 +258,15 @@ def refresh_feeds(request):
feeds[sub.feed.pk]['favicon_color'] = sub.feed.icon.color
feeds[sub.feed.pk]['favicon_fetching'] = bool(not (sub.feed.icon.not_found or sub.feed.icon.data))
diff = datetime.datetime.utcnow()-start
timediff = float("%s.%.2s" % (diff.seconds, (diff.microseconds / 1000)))
logging.user(request.user, "~FBRefreshing %s feeds (%s seconds)" % (user_subs.count(), timediff))
return {'feeds': feeds}
@json.json_view
def load_single_feed(request):
start = datetime.datetime.utcnow()
user = get_user(request)
offset = int(request.REQUEST.get('offset', 0))
limit = int(request.REQUEST.get('limit', 30))
@ -287,7 +296,6 @@ def load_single_feed(request):
force_update = request.GET.get('force_update', False)
start = datetime.datetime.utcnow()
stories = feed.get_stories(offset, limit)
if force_update:

View file

@ -121,16 +121,17 @@ class Feed(models.Model):
feed = None
def by_url(address):
duplicate_feed = DuplicateFeed.objects.filter(duplicate_address=address).order_by('pk')
if duplicate_feed:
feed = [duplicate_feed[0].feed]
else:
feed = cls.objects.filter(feed_address=address).order_by('pk')
feed = cls.objects.filter(feed_address=address)
if not feed:
duplicate_feed = DuplicateFeed.objects.filter(duplicate_address=address).order_by('pk')
if duplicate_feed:
feed = [duplicate_feed[0].feed]
return feed
url = urlnorm.normalize(url)
feed = by_url(url)
if feed:
feed = feed[0]
else:
@ -1025,6 +1026,9 @@ class DuplicateFeed(models.Model):
duplicate_address = models.CharField(max_length=255)
duplicate_feed_id = models.CharField(max_length=255, null=True)
feed = models.ForeignKey(Feed, related_name='duplicate_addresses')
def __unicode__(self):
return "%s: %s" % (self.feed, self.duplicate_address)
def merge_feeds(original_feed_id, duplicate_feed_id, force=False):
from apps.reader.models import UserSubscription, UserSubscriptionFolders, MUserStory

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View file

@ -1,10 +1,9 @@
{
"name": "NewsBlur",
"description": "RSS feed reading with intelligence.",
"version": "1.0",
"description": "Visual feed reading with intelligence.",
"version": "1.1",
"icons": {
"48": "48.png",
"128": "128.png"
"128": "logo_128.png"
},
"app": {
"urls": [

Binary file not shown.

View file

@ -75,7 +75,7 @@ body.NB-theme-serif #story_pane .NB-feed-story-content {
.NB-account {
position: absolute;
right: 0px;
top: 0px;
top: 55px;
width: 478px;
z-index: 1;
overflow: hidden;
@ -1644,7 +1644,9 @@ background: transparent;
text-shadow: 1px 1px 0 #e8e8e8;
}
#story_pane a.NB-feed-story-title:hover {
#story_pane a.NB-feed-story-title:hover,
#story_pane a.NB-feed-story-title:hover .NB-score-1,
#story_pane a.NB-feed-story-title:hover .NB-score--1 {
color: #1010A0;
}
@ -1658,12 +1660,13 @@ background: transparent;
}
#story_pane .NB-feed-story-tags {
margin: 6px 0 -6px;
margin: 7px 0 -6px;
overflow: hidden;
line-height: 12px;
height: 14px;
}
#story_pane .NB-feed-story-tag {
/* Grey */
float: left;
font-weight: normal;
font-size: 9px;
@ -1675,18 +1678,74 @@ background: transparent;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
cursor: pointer;
}
#story_pane .NB-feed-story-tag.NB-score-1 {
background-color: #34912E;
color: white;
text-shadow: 0 1px 0 #000;
opacity: .4;
/* Green */
background-color: #34912E;
color: white;
text-shadow: 0 1px 0 #000;
opacity: .4;
}
#story_pane .NB-feed-story-tag.NB-score--1 {
background-color: #A90103;
color: white;
text-shadow: 0 1px 0 #000;
opacity: .4;
/* Red */
background-color: #A90103;
color: white;
text-shadow: 0 1px 0 #000;
opacity: .4;
}
#story_pane .NB-feed-story-tag:hover {
/* Gray, active -> [Light] Green */
background-color: #89AE6E;
text-shadow: 0 1px 0 #000;
color: white;
opacity: .4;
}
#story_pane .NB-feed-story-tag.NB-score-1:hover {
/* Green, active -> [Light] Red */
background-color: #E35356;
color: white;
text-shadow: 0 1px 0 #000;
}
#story_pane .NB-feed-story-tag.NB-score--1:hover {
/* Red, active -> [Light] Grey */
background-color: #E2E2E2;
color: #A7A399;
text-shadow: 0 1px 0 #E9E9E9;
opacity: 1;
}
#story_pane .NB-feed-story-tag.NB-score-now-0:hover {
/* Grey, active */
background-color: #DBDBDB;
color: #9D9A95;
text-shadow: 0 1px 0 #E9E9E9;
opacity: 1;
}
#story_pane .NB-feed-story-tag.NB-score-now-1.NB-score-1:hover {
/* Green, active */
background-color: #34912E;
color: white;
text-shadow: 0 1px 0 #000;
}
#story_pane .NB-feed-story-tag.NB-score-now--1.NB-score--1:hover {
/* Red, active */
background-color: #A90103;
color: white;
text-shadow: 0 1px 0 #000;
opacity: .4;
}
#story_pane .NB-feed-story-title .NB-score-1 {
color: #34912E;
}
#story_pane .NB-feed-story-title .NB-score--1 {
color: #A90103;
}
#story_pane .NB-feed-story-author.NB-score-1 {
color: #34912E;
}
#story_pane .NB-feed-story-author.NB-score--1 {
color: #A90103;
}
#story_pane .NB-feed-story-header .NB-feed-story-date {
position: absolute;
@ -2397,25 +2456,40 @@ form.opml_import_form input {
left: 0;
}
#NB-splash .NB-splash-info {
width: 478px;
height: 55px;
background-color: white;
bottom: 0;
position: absolute;
right: 0;
z-index: 1;
}
#NB-splash .NB-splash-info.NB-splash-blur {
top: 0;
bottom: inherit;
}
#NB-splash .NB-splash-title {
position: absolute;
bottom: -1px;
height: 55px;
right: 0;
width: 235px;
right: 166px;
width: 312px;
z-index: 2;
}
#NB-splash .NB-splash-image {
margin: 0 auto;
height: 376px;
width: 600px;
background: transparent url('../img/reader/newsblur_splash_image.png') no-repeat 0 0;
#NB-splash .NB-splash-blur .NB-splash-title {
top: 0px;
bottom: inherit;
right: 166px;
width: 312px;
height: 55px;
}
#NB-splash .NB-splash-links {
position: absolute;
right: 236px;
width: 242px;
right: 0px;
width: 164px;
text-align: right;
bottom: 0;
display: block;
@ -2425,7 +2499,11 @@ form.opml_import_form input {
text-shadow: 1px 1px 0 #F0F0F0;
list-style: none;
white-space: nowrap;
z-index: 0;
z-index: 1;
}
#NB-splash .NB-splash-blur .NB-splash-links {
top: 0;
}
#NB-splash .NB-splash-links .NB-splash-link {
@ -2433,7 +2511,7 @@ form.opml_import_form input {
line-height: 12px;
margin: 1px 0;
padding: 0;
width: 121px;
width: 164px;
float: left;
}
#NB-splash .NB-splash-links .NB-splash-link.NB-first {
@ -2453,6 +2531,9 @@ form.opml_import_form input {
#NB-splash .NB-splash-links .NB-splash-link-github a:hover {
background: #E9ECF6 url('../img/reader/github_icon.png') no-repeat 0 0;
}
#NB-splash .NB-splash-links .NB-splash-link-blog a:hover {
background: #E9ECF6 url('../img/reader/ofbrooklyn_icon.png') no-repeat 0 0;
}
#NB-splash .NB-splash-links .NB-splash-link-twitter a:hover {
background: #E9ECF6 url('../img/reader/twitter_icon.png') no-repeat 0 0;
@ -2478,15 +2559,7 @@ a.NB-splash-link {
a.NB-splash-link:hover {
color: #A85B40;
}
.NB-splash-info {
background-color: white;
z-index: 1;
position: absolute;
right: 0;
bottom: 0;
width: 500px;
height: 56px;
}
/* ===================== */
/* = Splash Meta Links = */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 795 B

BIN
media/img/logo_128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
media/img/logo_newsblur.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

View file

@ -22,7 +22,7 @@
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
}
return self;
}

View file

@ -121,7 +121,7 @@
+ (int)computeStoryScore:(NSDictionary *)intelligence {
int score = 0;
int score_max = 0;
// int score_max = 0;
// [intelligence objectForKey:@"title"]
// var score_max = Math.max(story.intelligence['title'],
// story.intelligence['author'],

View file

@ -153,6 +153,7 @@
[results release];
[jsonString release];
}
[jsonString release];
}
@ -166,6 +167,7 @@
LogoutDelegate *ld = [LogoutDelegate alloc];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlR delegate:ld];
[urlConnection release];
[ld release];
}
#pragma mark -

View file

@ -24,7 +24,7 @@
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
}
return self;
}
@ -72,8 +72,8 @@
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
[error release];
// NSError *error = [request error];
// [error release];
}

View file

@ -392,10 +392,7 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = NewsBlur_Prefix.pch;
HEADER_SEARCH_PATHS = (
"~/three20/Build/Products/three20",
"~/Projects/three20/Build/Products/three20",
);
HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "NewsBlur-Info.plist";
OTHER_LDFLAGS = (
"-all_load",
@ -412,24 +409,9 @@
COPY_PHASE_STRIP = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = NewsBlur_Prefix.pch;
HEADER_SEARCH_PATHS = ../../../code/three20/Build/Products/three20;
HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "NewsBlur-Info.plist";
OTHER_LDFLAGS = (
"-force_load",
"../../../code/three20/Build/Products/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/libThree20UICommon.a",
"-force_load",
"../../../code/three20/Build/Products/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/libThree20.a",
"-force_load",
"../../../code/three20/Build/Products/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/libThree20UINavigator.a",
"-force_load",
"../../../code/three20/Build/Products/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/libThree20Core.a",
"-force_load",
"../../../code/three20/Build/Products/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/libThree20UI.a",
"-force_load",
"../../../code/three20/Build/Products/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/libThree20Network.a",
"-force_load",
"../../../code/three20/Build/Products/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/libThree20Style.a",
);
OTHER_LDFLAGS = "";
PRODUCT_NAME = NewsBlur;
VALIDATE_PRODUCT = YES;
};
@ -444,6 +426,7 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "~/code/three20/Build/Products/three20";
IPHONEOS_DEPLOYMENT_TARGET = 4.0;
OTHER_LDFLAGS = (
"-all_load",
"-ObjC",
@ -462,9 +445,10 @@
GCC_C_LANGUAGE_STANDARD = c99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.0;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
PREBINDING = NO;
SDKROOT = iphoneos3.1.3;
SDKROOT = iphoneos;
};
name = Release;
};

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:NewsBlur.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
BuildableName = "NewsBlur.app"
BlueprintName = "NewsBlur"
ReferencedContainer = "container:NewsBlur.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
displayScaleIsEnabled = "NO"
displayScale = "1.00"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
BuildableName = "NewsBlur.app"
BlueprintName = "NewsBlur"
ReferencedContainer = "container:NewsBlur.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
displayScaleIsEnabled = "NO"
displayScale = "1.00"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
BuildableName = "NewsBlur.app"
BlueprintName = "NewsBlur"
ReferencedContainer = "container:NewsBlur.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>NewsBlur.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>1D6058900D05DD3D006BFB54</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View file

@ -349,7 +349,7 @@ NEWSBLUR.AssetModel.Reader.prototype = {
}
},
refresh_feeds: function(callback, has_unfetched_feeds) {
refresh_feeds: function(callback, has_unfetched_feeds, feed_id) {
var self = this;
var pre_callback = function(data) {
@ -368,6 +368,9 @@ NEWSBLUR.AssetModel.Reader.prototype = {
data['favicons_fetching'] = favicons_fetching;
}
}
if (feed_id) {
data['feed_id'] = feed_id;
}
if (NEWSBLUR.Globals.is_authenticated) {
this.make_request('/reader/refresh_feeds', data, pre_callback);

View file

@ -42,7 +42,8 @@
this.counts = {
'feature_page': 0,
'unfetched_feeds': 0,
'fetched_feeds': 0
'fetched_feeds': 0,
'page_fill_outs': 0
};
this.cache = {
'iframe_stories': {},
@ -130,7 +131,8 @@
west__size: this.model.preference('feed_pane_size'),
west__onresize_end: $.rescope(this.save_feed_pane_size, this),
spacing_open: 4,
resizerDragOpacity: 0.6
resizerDragOpacity: 0.6,
enableCursorHotkey: false
});
leftLayout = $('.left-pane').layout({
@ -142,7 +144,8 @@
south__paneSelector: ".left-south",
south__size: 31,
south__resizable: false,
south__spacing_open: 0
south__spacing_open: 0,
enableCursorHotkey: false
});
leftCenterLayout = $('.left-center').layout({
@ -160,7 +163,8 @@
south__initClosed: true,
fxName: "slide",
fxSpeed: 1000,
fxSettings: { duration: 1000, easing: "easeInOutQuint" }
fxSettings: { duration: 1000, easing: "easeInOutQuint" },
enableCursorHotkey: false
});
rightLayout = $('.right-pane').layout({
@ -169,7 +173,8 @@
south__size: this.model.preference('story_titles_pane_size'),
south__onresize_end: $.rescope(this.save_story_titles_pane_size, this),
spacing_open: 10,
resizerDragOpacity: 0.6
resizerDragOpacity: 0.6,
enableCursorHotkey: false
});
contentLayout = this.$s.$content_pane.layout({
@ -177,7 +182,8 @@
south__paneSelector: ".content-north",
south__size: 30,
spacing_open: 0,
resizerDragOpacity: 0.6
resizerDragOpacity: 0.6,
enableCursorHotkey: false
});
$('.right-pane').hide();
@ -1343,13 +1349,17 @@
'prefetch_iteration': 0,
'feed_title_floater_feed_id': null,
'feed_title_floater_story_id': null,
'last_feed_view_story_feed_id': null
'last_feed_view_story_feed_id': null,
$feed_in_feed_list: {},
$feed_counts_in_feed_list: {}
});
$.extend(this.counts, {
'page_fill_outs': 0
});
this.active_feed = null;
this.active_story = null;
this.cache.$feed_in_feed_list = null;
this.cache.$feed_counts_in_feed_list = null;
this.$s.$story_titles.data('page', 0);
this.$s.$story_titles.data('feed_id', null);
this.$s.$feed_stories.scrollTop(0);
@ -1999,20 +2009,21 @@
},
update_read_count: function(story_id, feed_id, unread, previously_read) {
// NEWSBLUR.log(['update_read_count', feed_id, unread, previously_read]);
if (previously_read) return;
var feed = this.model.get_feed(feed_id);
var $feed_list = this.$s.$feed_list;
var $feed = this.cache.$feed_in_feed_list || this.find_feed_in_feed_list(feed_id);
var $feed_counts = this.cache.$feed_counts_in_feed_list || $('.feed_counts_floater', $feed);
var $feed = this.cache.$feed_in_feed_list[feed_id] || this.find_feed_in_feed_list(feed_id);
var $feed_counts = this.cache.$feed_counts_in_feed_list[feed_id] || $('.feed_counts_floater', $feed);
var $story_title = this.find_story_in_story_titles(story_id);
var $content_pane = this.$s.$content_pane;
var unread_count_positive = feed.ps;
var unread_count_neutral = feed.nt;
var unread_count_negative = feed.ng;
this.cache.$feed_in_feed_list = $feed;
this.cache.$feed_counts_in_feed_list = $feed_counts;
this.cache.$feed_in_feed_list[feed_id] = $feed;
this.cache.$feed_counts_in_feed_list[feed_id] = $feed_counts;
$story_title.toggleClass('read', !unread);
// NEWSBLUR.log(['marked read', unread_count_positive, unread_count_neutral, unread_count_negative, $story_title.is('.NB-story-positive'), $story_title.is('.NB-story-neutral'), $story_title.is('.NB-story-negative')]);
@ -2132,20 +2143,10 @@
}
},
mark_story_as_like: function(story_id, feed_id) {
open_story_trainer: function(story_id, feed_id) {
feed_id = feed_id || this.model.get_story(story_id).story_feed_id;
NEWSBLUR.classifier = new NEWSBLUR.ReaderClassifierStory(story_id, feed_id, {
'score': 1,
'feed_loaded': !this.flags['river_view']
});
},
mark_story_as_dislike: function(story_id, feed_id) {
feed_id = feed_id || this.active_feed;
NEWSBLUR.classifier = new NEWSBLUR.ReaderClassifierStory(story_id, feed_id, {
'score': -1,
'feed_loaded': !this.flags['river_view']
});
},
@ -2354,13 +2355,6 @@
$.make('span', { className: 'story_date' }, story.short_parsed_date),
$.make('span', { className: 'story_id' }, ''+story.id),
$.make('div', { className: 'NB-story-manage-icon' })
// $.make('div', { className: 'NB-story-sentiment NB-story-like', title: 'What I like about this story...' }),
// $.make('div', {
// className: 'NB-story-sentiment NB-story-star',
// title: (story.starred
// ? 'Remove bookmark'
// : 'Save this story for later')
// })
]).data('story_id', story.id).data('feed_id', story.story_feed_id);
if (unread_view > score) {
@ -2499,6 +2493,8 @@
$story.addClass('NB-story-negative');
}
$('.NB-feed-story-tags', $story).replaceWith(this.make_story_feed_tags(story));
$('.NB-feed-story-author', $story).replaceWith(this.make_story_feed_author(story));
$('.NB-feed-story-title', $story).replaceWith(this.make_story_feed_title(story));
}, this);
_.each(this.cache.feed_view_stories, _.bind(function($story, story_id) {
@ -2718,7 +2714,12 @@
($last.length == 0 ||
($('#story_titles').scrollTop() == 0 &&
$last.position().top + $last.height() < container_height))) {
_.delay(_.bind(this.load_page_of_feed_stories, this), 250);
if (this.counts['page_fill_outs'] < 8) {
this.counts['page_fill_outs'] += 1;
_.delay(_.bind(this.load_page_of_feed_stories, this), 250);
} else {
this.append_story_titles_endbar();
}
}
},
@ -2969,13 +2970,13 @@
.toggleClass('NB-inverse', this.is_feed_floater_gradient_light(feed)),
$.make('div', { className: 'NB-feed-story-header-info' }, [
(story.story_authors &&
$.make('div', { className: 'NB-feed-story-author' }, story.story_authors)),
this.make_story_feed_author(story)),
(story.story_tags && story.story_tags.length && this.make_story_feed_tags(story)),
$.make('div', { className: 'NB-feed-story-title-container' }, [
$.make('div', { className: 'NB-feed-story-sentiment' }),
$.make('div', { className: 'NB-feed-story-manage-icon' }),
// $.make('div', { className: 'NB-feed-story-sentiment NB-feed-story-sentiment-animate' }),
$.make('a', { className: 'NB-feed-story-title', href: story.story_permalink }, story.story_title)
this.make_story_feed_title(story)
]),
(story.long_parsed_date &&
$.make('span', { className: 'NB-feed-story-date' }, story.long_parsed_date)),
@ -3029,16 +3030,75 @@
this.show_stories_preference_in_feed_view(true);
},
make_story_feed_title: function(story) {
var title = story.story_title;
_.each(this.model.classifiers.titles, function(score, title_classifier) {
if (title.indexOf(title_classifier) != -1) {
title = title.replace(title_classifier, '<span class="NB-score-'+score+'">'+title_classifier+'</span>');
}
});
return $.make('a', { className: 'NB-feed-story-title', href: story.story_permalink }, title);
},
make_story_feed_author: function(story) {
var score = this.model.classifiers.authors[story.story_authors];
return $.make('div', {
className: 'NB-feed-story-author ' + (!!score && 'NB-score-'+score)
}, story.story_authors);
},
make_story_feed_tags: function(story) {
var feed_tags = this.model.classifiers.tags;
return $.make('div', { className: 'NB-feed-story-tags' },
_.map(story.story_tags, function(tag) {
var score = feed_tags[tag];
return $.make('div', {
className: 'NB-feed-story-tag ' + (!!score && 'NB-score-'+score || '')
}, tag);
}));
var feed_tags = this.model.classifiers.tags;
return $.make('div', { className: 'NB-feed-story-tags' },
_.map(story.story_tags, function(tag) {
var score = feed_tags[tag];
return $.make('div', {
className: 'NB-feed-story-tag ' + (!!score && 'NB-score-'+score || '')
}, tag).data('tag', tag);
}));
},
preserve_classifier_color: function($story, value, score) {
var $t;
$('.NB-feed-story-tag', $story).each(function() {
if ($(this).data('tag') == value) {
$t = $(this);
return false;
}
});
$t.removeClass('NB-score-now-1')
.removeClass('NB-score-now--1')
.removeClass('NB-score-now-0')
.addClass('NB-score-now-'+score)
.one('mouseleave', function() {
$t.removeClass('NB-score-now-'+score);
});
_.defer(function() {
$t.one('mouseenter', function() {
$t.removeClass('NB-score-now-'+score);
});
});
},
save_classifier: function(type, value, score, feed_id) {
var data = {
'feed_id': feed_id
};
if (score == 0) {
data['remove_like_'+type] = value;
} else if (score == 1) {
data['like_'+type] = value;
} else if (score == -1) {
data['dislike_'+type] = value;
}
this.model.classifiers[type+'s'][value] = score;
this.model.save_classifier_publisher(data, _.bind(function(resp) {
this.force_feeds_refresh(null, true, feed_id);
}, this));
this.recalculate_story_scores(feed_id);
},
show_correct_feed_in_feed_title_floater: function(story) {
@ -4209,41 +4269,6 @@
}, 550);
}
},
update_opinions: function($modal, feed_id) {
var self = this;
$('input[type=checkbox]', $modal).each(function() {
var $this = $(this);
var name = $this.attr('name').replace(/^(dis)?like_/, '');
var score = /^dislike/.test($this.attr('name')) ? -1 : 1;
var value = $this.val();
var checked = $this.attr('checked');
if (checked) {
if (name == 'tag') {
self.model.classifiers.tags[value] = score;
} else if (name == 'title') {
self.model.classifiers.titles[value] = score;
} else if (name == 'author') {
self.model.classifiers.authors[value] = score;
} else if (name == 'feed') {
self.model.classifiers.feeds[feed_id] = score;
}
} else {
if (name == 'tag' && self.model.classifiers.tags[value] == score) {
delete self.model.classifiers.tags[value];
} else if (name == 'title' && self.model.classifiers.titles[value] == score) {
delete self.model.classifiers.titles[value];
} else if (name == 'author' && self.model.classifiers.authors[value] == score) {
delete self.model.classifiers.authors[value];
} else if (name == 'feed' && self.model.classifiers.feeds[feed_id] == score) {
delete self.model.classifiers.feeds[feed_id];
}
}
});
},
// ===================
// = Feed Refreshing =
@ -4271,7 +4296,7 @@
if (self.active_feed == feed_id) {
self.open_feed(feed_id, true, $new_feed);
}
}, true);
}, true, feed_id);
},
setup_feed_refresh: function(new_feeds) {
@ -4297,7 +4322,7 @@
}, refresh_interval);
},
force_feeds_refresh: function(callback, update_all) {
force_feeds_refresh: function(callback, replace_active_feed, feed_id) {
if (callback) {
this.cache.refresh_callback = callback;
} else {
@ -4307,11 +4332,11 @@
this.flags['pause_feed_refreshing'] = true;
this.model.refresh_feeds(_.bind(function(updated_feeds) {
this.post_feed_refresh(updated_feeds, update_all);
}, this), this.flags['has_unfetched_feeds']);
this.post_feed_refresh(updated_feeds, replace_active_feed);
}, this), this.flags['has_unfetched_feeds'], feed_id);
},
post_feed_refresh: function(updated_feeds, update_all) {
post_feed_refresh: function(updated_feeds, replace_active_feed) {
var feeds = this.model.feeds;
if (this.cache.refresh_callback && $.isFunction(this.cache.refresh_callback)) {
@ -4326,12 +4351,20 @@
var $feed = this.make_feed_title_line(feed, true, 'feed');
var $feed_on_page = this.find_feed_in_feed_list(feed_id);
if (feed_id == this.active_feed && !update_all) {
if (feed_id == this.active_feed) {
NEWSBLUR.log(['UPDATING INLINE', feed.feed_title, $feed, $feed_on_page]);
// var limit = $('.story', this.$s.$story_titles).length;
// this.model.refresh_feed(feed_id, $.rescope(this.post_refresh_active_feed, this), limit);
// $feed_on_page.replaceWith($feed);
// this.mark_feed_as_selected(this.active_feed, $feed);
if (!replace_active_feed) {
// var limit = $('.story', this.$s.$story_titles).length;
// this.model.refresh_feed(feed_id, $.rescope(this.post_refresh_active_feed, this), limit);
// Set the unread counts to what the client thinks they are, so when
// the counts can be updated, they will force a refresh of the feed.
this.model.feeds[feed_id].ps = parseInt($('.unread_count_positive', $feed_on_page).text(), 10);
this.model.feeds[feed_id].nt = parseInt($('.unread_count_neutral', $feed_on_page).text(), 10);
this.model.feeds[feed_id].ng = parseInt($('.unread_count_negative', $feed_on_page).text(), 10);
} else {
$feed_on_page.replaceWith($feed);
this.mark_feed_as_selected(this.active_feed, $feed);
}
} else {
if (!this.flags['has_unfetched_feeds']) {
NEWSBLUR.log(['UPDATING', feed.feed_title, $feed, $feed_on_page]);
@ -4866,13 +4899,6 @@
story_prevent_bubbling = true;
self.show_manage_menu('story', $t);
});
$.targetIs(e, { tagSelector: '.NB-story-like' }, function($t, $p){
e.preventDefault();
var story_id = $t.closest('.story').data('story_id');
var feed_id = $t.closest('.story').data('feed_id');
self.mark_story_as_like(story_id, feed_id);
story_prevent_bubbling = true;
});
$.targetIs(e, { tagSelector: '.NB-menu-manage-story-open' }, function($t, $p){
e.preventDefault();
var story_id = $t.closest('.NB-menu-manage-story').data('story_id');
@ -4890,23 +4916,19 @@
}
story_prevent_bubbling = true;
});
$.targetIs(e, { tagSelector: 'a.button.like' }, function($t, $p){
e.preventDefault();
var story_id = self.$s.$story_pane.data('story_id');
var feed_id = $t.closest('.story').data('feed_id');
self.mark_story_as_like(story_id, feed_id);
story_prevent_bubbling = true;
});
$.targetIs(e, { tagSelector: 'a.button.dislike' }, function($t, $p){
e.preventDefault();
var story_id = self.$s.$story_pane.data('story_id');
var feed_id = $t.closest('.story').data('feed_id');
self.mark_story_as_dislike(story_id, feed_id);
story_prevent_bubbling = true;
});
if (story_prevent_bubbling) return false;
$.targetIs(e, { tagSelector: '.NB-feed-story-tag' }, function($t, $p){
e.preventDefault();
var $story = $t.closest('.NB-feed-story');
var feed_id = $story.data('feed_id');
var tag = $t.data('tag');
var score = $t.hasClass('NB-score-1') ? -1 : $t.hasClass('NB-score--1') ? 0 : 1;
self.save_classifier('tag', tag, score, feed_id);
self.preserve_classifier_color($story, tag, score);
});
$.targetIs(e, { tagSelector: '.story' }, function($t, $p){
e.preventDefault();
var story_id = $('.story_id', $t).text();
@ -4961,7 +4983,7 @@
if (!$t.hasClass('NB-disabled')) {
var feed_id = $t.closest('.NB-menu-manage').data('feed_id');
var story_id = $t.closest('.NB-menu-manage').data('story_id');
self.mark_story_as_like(story_id, feed_id);
self.open_story_trainer(story_id, feed_id);
}
});
$.targetIs(e, { tagSelector: '.NB-menu-manage-trainer' }, function($t, $p){

View file

@ -56,6 +56,9 @@ NEWSBLUR.ReaderAddFeed.prototype = {
])
])
]),
// $.make('div', { className: 'NB-fieldset-divider' }, [
// 'Google Reader and OPML'
// ]),
$.make('div', { className: 'NB-fieldset NB-anonymous-ok NB-modal-submit' }, [
$.make('h5', [
'Import feeds'
@ -72,7 +75,10 @@ NEWSBLUR.ReaderAddFeed.prototype = {
])
]),
$.make('div', { className: 'NB-fieldset NB-add-opml NB-modal-submit' }, [
$.make('h5', 'Upload OPML'),
$.make('h5', [
'Upload OPML',
$.make('a', { className: 'NB-right NB-splash-link', href: NEWSBLUR.URLs['opml-export'] }, 'Export OPML')
]),
$.make('div', { className: 'NB-fieldset-fields' }, [
$.make('form', { method: 'post', enctype: 'multipart/form-data', className: 'NB-add-form' }, [
$.make('div', { className: 'NB-loading' }),
@ -224,7 +230,7 @@ NEWSBLUR.ReaderAddFeed.prototype = {
// NEWSBLUR.log(['Uploading']);
$.ajaxFileUpload({
url: '/import/opml_upload',
url: NEWSBLUR.URLs['opml-upload'],
secureuri: false,
fileElementId: 'opml_file_input',
dataType: 'text',

View file

@ -1,6 +1,5 @@
NEWSBLUR.ReaderClassifierTrainer = function(options) {
var defaults = {
'score': 1,
'training': true
};
@ -14,14 +13,12 @@ NEWSBLUR.ReaderClassifierTrainer = function(options) {
this.trainer_iterator = -1;
this.feed_id = null;
this.options = $.extend({}, defaults, options);
this.score = this.options['score'];
this.model = NEWSBLUR.AssetModel.reader();
this.runner_trainer();
};
NEWSBLUR.ReaderClassifierFeed = function(feed_id, options) {
var defaults = {
'score': 1,
'training': false,
'feed_loaded': true
};
@ -36,7 +33,6 @@ NEWSBLUR.ReaderClassifierFeed = function(feed_id, options) {
this.feed_id = feed_id;
this.trainer_iterator = -1;
this.options = $.extend({}, defaults, options);
this.score = this.options['score'];
this.model = NEWSBLUR.AssetModel.reader();
this.runner_feed();
};
@ -44,7 +40,6 @@ NEWSBLUR.ReaderClassifierFeed = function(feed_id, options) {
NEWSBLUR.ReaderClassifierStory = function(story_id, feed_id, options) {
var defaults = {
'score': 1,
'feed_loaded': true
};
@ -59,7 +54,6 @@ NEWSBLUR.ReaderClassifierStory = function(story_id, feed_id, options) {
this.feed_id = feed_id;
this.trainer_iterator = -1;
this.options = $.extend({}, defaults, options);
this.score = this.options['score'];
this.model = NEWSBLUR.AssetModel.reader();
this.runner_story();
};
@ -373,7 +367,6 @@ var classifier_prototype = {
)
]),
(this.options['training'] && $.make('div', { className: 'NB-modal-submit' }, [
$.make('input', { name: 'score', value: this.score, type: 'hidden' }),
$.make('input', { name: 'feed_id', value: this.feed_id, type: 'hidden' }),
$.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-back' }, $.entity('&laquo;') + ' Back'),
$.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-green NB-modal-submit-next NB-modal-submit-save' }, 'Save & Next '+$.entity('&raquo;')),
@ -395,7 +388,6 @@ var classifier_prototype = {
var self = this;
var story = this.story;
var feed = this.feed;
var opinion = (this.score == 1 ? 'like_' : 'dislike_');
// NEWSBLUR.log(['Make Story', story, feed]);
@ -419,19 +411,19 @@ var classifier_prototype = {
(story.story_authors && $.make('div', { className: 'NB-modal-field NB-fieldset' }, [
$.make('h5', 'Story Author'),
$.make('div', { className: 'NB-fieldset-fields NB-classifiers' },
this.make_authors([story.story_authors], opinion)
this.make_authors([story.story_authors])
)
])),
(story.story_tags.length && $.make('div', { className: 'NB-modal-field NB-fieldset' }, [
$.make('h5', 'Story Categories &amp; Tags'),
$.make('div', { className: 'NB-classifier-tags NB-fieldset-fields NB-classifiers' },
this.make_tags(story.story_tags, opinion)
this.make_tags(story.story_tags)
)
])),
$.make('div', { className: 'NB-modal-field NB-fieldset' }, [
$.make('h5', 'Everything by This Publisher'),
$.make('div', { className: 'NB-fieldset-fields NB-classifiers' },
this.make_publisher(feed, opinion)
this.make_publisher(feed)
)
]),
$.make('div', { className: 'NB-modal-submit' }, [
@ -441,11 +433,7 @@ var classifier_prototype = {
' or ',
$.make('a', { href: '#', className: 'NB-modal-cancel' }, 'cancel')
])
]).bind('submit', function(e) {
e.preventDefault();
self.save_story();
return false;
})
])
)
]);
},
@ -488,7 +476,7 @@ var classifier_prototype = {
return $titles;
},
make_authors: function(authors, opinion) {
make_authors: function(authors) {
var $authors = [];
for (var a in authors) {
@ -555,7 +543,7 @@ var classifier_prototype = {
return this.make_tags(tags);
},
make_publisher: function(publisher, opinion) {
make_publisher: function(publisher) {
var $publisher = this.make_classifier(publisher.feed_title, this.feed_id, 'feed');
return $publisher;
},
@ -777,7 +765,7 @@ var classifier_prototype = {
});
$.targetIs(e, { tagSelector: '.NB-modal-submit-save.NB-modal-submit-next' }, function($t, $p){
e.preventDefault();
self.save_publisher(true);
self.save(true);
self.load_next_feed_in_trainer();
self.update_homepage_counts();
});
@ -794,7 +782,7 @@ var classifier_prototype = {
$.targetIs(e, { tagSelector: '.NB-modal-submit-close' }, function($t, $p){
e.preventDefault();
self.save_publisher();
self.save();
});
$.targetIs(e, { tagSelector: '.NB-modal-submit-end' }, function($t, $p){
@ -807,7 +795,7 @@ var classifier_prototype = {
} else {
$.targetIs(e, { tagSelector: '.NB-modal-submit-save:not(.NB-modal-submit-next)' }, function($t, $p){
e.preventDefault();
self.save_publisher();
self.save();
return false;
});
}
@ -847,13 +835,12 @@ var classifier_prototype = {
return data;
},
save_publisher: function(keep_modal_open) {
save: function(keep_modal_open) {
var self = this;
var $save = $('.NB-modal-submit-save', this.$modal);
var data = this.serialize_classifier();
var feed_id = this.feed_id;
NEWSBLUR.reader.update_opinions(this.$modal, feed_id);
if (this.options['training']) {
this.cache[this.feed_id] = this.$modal.clone();
@ -863,6 +850,7 @@ var classifier_prototype = {
}
$save.addClass('NB-disabled').attr('disabled', true);
this.update_opinions();
this.model.save_classifier_publisher(data, function() {
if (!keep_modal_open) {
NEWSBLUR.reader.recalculate_story_scores(feed_id);
@ -875,21 +863,38 @@ var classifier_prototype = {
});
},
save_story: function() {
update_opinions: function() {
var self = this;
var $save = $('.NB-modal-submit-save', this.$modal);
var story_id = this.story_id;
var data = this.serialize_classifier();
var feed_id = this.feed_id;
NEWSBLUR.reader.update_opinions(this.$modal, feed_id);
$('input[type=checkbox]', this.$modal).each(function() {
var $this = $(this);
var name = $this.attr('name').replace(/^(dis)?like_/, '');
var score = /^dislike/.test($this.attr('name')) ? -1 : 1;
var value = $this.val();
var checked = $this.attr('checked');
$save.text('Saving...').addClass('NB-disabled').attr('disabled', true);
this.model.save_classifier_story(story_id, data, function() {
NEWSBLUR.reader.force_feeds_refresh(null, true);
NEWSBLUR.reader.recalculate_story_scores(feed_id);
// NEWSBLUR.reader.open_feed(self.feed_id, true);
$.modal.close();
if (checked) {
if (name == 'tag') {
self.model.classifiers.tags[value] = score;
} else if (name == 'title') {
self.model.classifiers.titles[value] = score;
} else if (name == 'author') {
self.model.classifiers.authors[value] = score;
} else if (name == 'feed') {
self.model.classifiers.feeds[feed_id] = score;
}
} else {
if (name == 'tag' && self.model.classifiers.tags[value] == score) {
delete self.model.classifiers.tags[value];
} else if (name == 'title' && self.model.classifiers.titles[value] == score) {
delete self.model.classifiers.titles[value];
} else if (name == 'author' && self.model.classifiers.authors[value] == score) {
delete self.model.classifiers.authors[value];
} else if (name == 'feed' && self.model.classifiers.feeds[feed_id] == score) {
delete self.model.classifiers.feeds[feed_id];
}
}
});
}

View file

@ -121,7 +121,7 @@ NEWSBLUR.ReaderMarkRead.prototype = {
$.modal.close();
NEWSBLUR.reader.force_feeds_refresh(function() {
NEWSBLUR.reader.finish_count_unreads_after_import();
});
}, true);
});
} else {
$.modal.close();

View file

@ -261,6 +261,15 @@ NEWSBLUR.ReaderPreferences.prototype = {
'Sharing services'
])
]),
$.make('div', { className: 'NB-preference NB-preference-opml' }, [
$.make('div', { className: 'NB-preference-options' }, [
$.make('a', { className: 'NB-splash-link', href: NEWSBLUR.URLs['opml-export'] }, 'Download OPML')
]),
$.make('div', { className: 'NB-preference-label'}, [
'Backup Your Sites',
$.make('div', { className: 'NB-preference-sublabel' }, 'Download this XML file as a backup.')
])
]),
$.make('div', { className: 'NB-preference NB-preference-password' }, [
$.make('div', { className: 'NB-preference-options' }, [
$.make('div', { className: 'NB-preference-option' }, [

View file

@ -41,6 +41,8 @@
};
NEWSBLUR.URLs = {
'google-reader-authorize': "{% url google-reader-authorize %}",
'opml-upload': "{% url opml-upload %}",
'opml-export': "{% url opml-export %}",
'domain': "{% current_domain %}"
};
</script>

View file

@ -13,10 +13,19 @@ $(document).ready(function() {
</script>
<h1 class="NB-splash-heading">NewsBlur</h1>
<h2 class="NB-splash-heading">- A feed reader with intelligence.</h2>
<h2 class="NB-splash-heading">- A visual feed reader with intelligence.</h2>
<div id="NB-splash">
<div class="NB-splash-info NB-splash-blur">
<img class="NB-splash-title" src="{{ MEDIA_URL }}/img/logo_newsblur_blur.png" />
<ul class="NB-splash-links">
<li class="NB-splash-link NB-first NB-splash-link-twitter"><a href="http://twitter.com/samuelclay">@samuelclay</a></li>
<li class="NB-splash-link NB-first NB-splash-link-twitter"><a href="http://twitter.com/newsblur">@newsblur</a></li>
<li class="NB-splash-link NB-first NB-splash-link-github"><a href="http://github.com/samuelclay">GitHub</a></li>
</ul>
</div>
<div class="NB-modules-center">
{% if recommended_feed %}
{% render_recommended_feed recommended_feed %}
@ -174,7 +183,7 @@ $(document).ready(function() {
<table class="NB-howitworks-page-description">
<tr>
<td>
{% filter typogrify %}Use the iPhone app, available before January 2011.{% endfilter %}
{% filter typogrify %}Use the iPhone app, available in Summer 2011.{% endfilter %}
</td>
</tr>
</table>
@ -196,7 +205,7 @@ $(document).ready(function() {
</div>
{% else %}
<div class="NB-module NB-module-stats">
<h5 class="NB-module-header">
Welcome, {{ user.username }}
@ -304,15 +313,15 @@ $(document).ready(function() {
</div>
<div class="NB-splash-info">
<img class="NB-splash-title" src="{{ MEDIA_URL }}/img/logo_newsblur.png" />
<ul class="NB-splash-links">
<li class="NB-splash-link NB-first NB-splash-link-twitter"><a href="http://twitter.com/samuelclay">@samuelclay</a></li>
{# <li class="NB-splash-link NB-first NB-splash-link-twitter"><a href="http://twitter.com/samuelclay">@samuelclay</a></li> #}
<li class="NB-splash-link NB-splash-meta-faq"><a href="#faq">FAQ</a></li>
<li class="NB-splash-link NB-splash-meta-about"><a href="#about">About</a></li>
<li class="NB-splash-link NB-first NB-splash-link-twitter"><a href="http://twitter.com/newsblur">@newsblur</a></li>
<li class="NB-splash-link NB-splash-meta-faq"><a href="#faq">Questions</a></li>
<li class="NB-splash-link NB-first NB-splash-link-github"><a href="http://github.com/samuelclay">GitHub</a></li>
<li class="NB-splash-link"><a href="mailto:samuel@ofbrooklyn.com">Email Samuel</a></li>
<li class="NB-splash-link NB-splash-link-blog"><a href="http://www.@ofbrooklyn.com">The Blog</a></li>
{# <li class="NB-splash-link NB-first NB-splash-link-twitter"><a href="http://twitter.com/newsblur">@newsblur</a></li> #}
{# <li class="NB-splash-link NB-first NB-splash-link-github"><a href="http://github.com/samuelclay">GitHub</a></li> #}
</ul>
<img class="NB-splash-title" src="{{ MEDIA_URL }}/img/reader/newsblur_logo.png" />
</div>
</div>

View file

@ -153,7 +153,7 @@ def format_relative_date(date, future=False):
return "%s hours %s" % ((((diff.seconds / 60) + 15) / 60),
'' if future else 'ago')
def add_object_to_folder(obj, folder, folders):
def add_object_to_folder(obj, folder, folders, added=False):
if not folder and obj not in folders:
folders.append(obj)
return folders
@ -161,9 +161,10 @@ def add_object_to_folder(obj, folder, folders):
for k, v in enumerate(folders):
if isinstance(v, dict):
for f_k, f_v in v.items():
if f_k == folder and obj not in f_v:
if f_k == folder and obj not in f_v and not added:
f_v.append(obj)
folders[k][f_k] = add_object_to_folder(obj, folder, f_v)
added = True
folders[k][f_k] = add_object_to_folder(obj, folder, f_v, added)
return folders
def mail_feed_error_to_admin(feed, e):