Merge branch 'master' into recommended
Conflicts: media/css/reader.css
|
@ -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:
|
||||
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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" % (
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 3.5 KiB |
BIN
extensions/chrome/favicon.png
Normal file
After Width: | Height: | Size: 795 B |
BIN
extensions/chrome/logo_128.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
extensions/chrome/logo_512.png
Normal file
After Width: | Height: | Size: 62 KiB |
|
@ -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": [
|
||||
|
|
BIN
media/Erbar LT Bold Condensed.ttf
Normal 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 = */
|
||||
|
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 795 B |
BIN
media/img/logo_128.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
media/img/logo_newsblur.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
media/img/logo_newsblur_512.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
media/img/logo_newsblur_blur.png
Normal file
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 106 B |
BIN
media/img/originals/logo.png
Normal file
After Width: | Height: | Size: 238 KiB |
BIN
media/img/originals/logo.psd
Normal file
BIN
media/img/originals/logo_16.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
media/img/originals/logo_16.psd
Normal file
BIN
media/img/originals/newsblur_logo_original.png
Normal file
After Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 61 KiB |
BIN
media/img/reader/ofbrooklyn_icon.png
Normal file
After Width: | Height: | Size: 961 B |
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -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 -
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
7
media/iphone/NewsBlur.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:NewsBlur.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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('«') + ' Back'),
|
||||
$.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-green NB-modal-submit-next NB-modal-submit-save' }, 'Save & Next '+$.entity('»')),
|
||||
|
@ -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 & 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];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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' }, [
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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):
|
||||
|
|