Rendering feeds and folders, including toplevel. Making feed count a separate view. Also making feed list header view, hooking up both buttons.

This commit is contained in:
Samuel Clay 2012-05-18 16:59:39 -07:00
parent fe5c286de7
commit a380bfcd0c
12 changed files with 431 additions and 335 deletions

View file

@ -437,6 +437,9 @@ body.NB-theme-serif #story_pane .NB-feed-story-content {
padding: 0 0 0 22px;
list-style: none;
}
.NB-feedlist ul.folder.NB-root {
padding-left: 0;
}
.NB-feedlist .folder_title {
padding: 4px 0 4px 22px;

View file

@ -276,7 +276,7 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
NEWSBLUR.log(['subscriptions', feeds, subscriptions]);
self.flags['favicons_fetching'] = self.feeds.any(function(feed) { return feed.get('favicons_fetching'); });
self.folders = new NEWSBLUR.Collections.Folders();
self.folders = new NEWSBLUR.Collections.Folders([]);
self.folders.parse(subscriptions.folders);
self.starred_count = subscriptions.starred_count;
self.social_feeds.reset(subscriptions.social_feeds);

View file

@ -2,7 +2,6 @@ NEWSBLUR.Views.FeedList = Backbone.View.extend({
initialize: function() {
this.$s = NEWSBLUR.reader.$s;
this.model = NEWSBLUR.assets;
if (!$('#feed_list').length) return;
$('.NB-callout-ftux .NB-callout-text').text('Loading feeds...');
@ -10,93 +9,116 @@ NEWSBLUR.Views.FeedList = Backbone.View.extend({
NEWSBLUR.reader.flags['favicons_downloaded'] = false;
NEWSBLUR.assets.feeds.bind('reset', _.bind(function() {
this.make_feeds();
this.make_social_feeds();
this.load_router();
}, this));
NEWSBLUR.assets.social_feeds.bind('reset', _.bind(function() {
this.make_social_feeds();
}, this));
NEWSBLUR.assets.load_feeds();
},
make_feeds: function() {
var self = this;
var $feed_list = this.$s.$feed_list;
var folders = this.model.folders;
var feeds = this.model.feeds;
var folders = NEWSBLUR.assets.folders;
var feeds = NEWSBLUR.assets.feeds;
// NEWSBLUR.log(['Making feeds', {'folders': folders, 'feeds': feeds}]);
$feed_list.empty();
this.$s.$story_taskbar.css({'display': 'block'});
var $feeds = new NEWSBLUR.Views.Folder(this.model.folders).render().el;
var $feeds = new NEWSBLUR.Views.Folder({collection: folders, root: true}).render().el;
$feed_list.css({
'display': 'block',
'opacity': 0
});
$feed_list.html($feeds);
$feed_list.animate({'opacity': 1}, {'duration': 700});
this.count_collapsed_unread_stories();
this.hover_over_feed_titles($feed_list);
// this.count_collapsed_unread_stories();
// this.hover_over_feed_titles();
this.$s.$feed_link_loader.fadeOut(250);
if (folders.length) {
$('.NB-task-manage').removeClass('NB-disabled');
$('.NB-callout-ftux').fadeOut(500);
}
this.open_dialog_after_feeds_loaded();
if (NEWSBLUR.Globals.is_authenticated && this.model.flags['has_chosen_feeds']) {
NEWSBLUR.reader.open_dialog_after_feeds_loaded();
if (NEWSBLUR.Globals.is_authenticated && NEWSBLUR.assets.flags['has_chosen_feeds']) {
_.delay(_.bind(this.start_count_unreads_after_import, this), 1000);
this.flags['refresh_inline_feed_delay'] = true;
this.force_feeds_refresh($.rescope(this.finish_count_unreads_after_import, this), true);
}
if (folders.length) {
this.load_sortable_feeds();
this.update_header_counts();
_.delay(_.bind(this.update_starred_count, this), 250);
NEWSBLUR.reader.check_hide_getting_started();
$('.NB-task-manage').removeClass('NB-disabled');
$('.NB-callout-ftux').fadeOut(500);
// this.load_sortable_feeds();
_.delay(_.bind(NEWSBLUR.reader.update_starred_count, NEWSBLUR.reader), 250);
// NEWSBLUR.reader.check_hide_getting_started();
}
if (this.flags['showing_feed_in_tryfeed_view'] || this.flags['showing_social_feed_in_tryfeed_view']) {
this.hide_tryfeed_view();
this.force_feed_refresh();
}
_.defer(_.bind(function() {
this.make_feed_favicons();
// this.model.load_feed_favicons($.rescope(this.make_feed_favicons, this), this.flags['favicons_downloaded'], this.model.flags['has_chosen_feeds']);
if (this.socket) {
this.send_socket_active_feeds();
} else {
var force_socket = NEWSBLUR.Globals.is_admin;
this.setup_socket_realtime_unread_counts(force_socket);
}
}, this));
// if (NEWSBLUR.reader.flags['showing_feed_in_tryfeed_view'] || NEWSBLUR.reader.flags['showing_social_feed_in_tryfeed_view']) {
// NEWSBLUR.reader.hide_tryfeed_view();
// NEWSBLUR.reader.force_feed_refresh();
// }
// _.defer(_.bind(function() {
// NEWSBLUR.reader.make_feed_favicons();
// // NEWSBLUR.assets.load_feed_favicons($.rescope(this.make_feed_favicons, this), this.flags['favicons_downloaded'], NEWSBLUR.assets.flags['has_chosen_feeds']);
// if (NEWSBLUR.reader.socket) {
// NEWSBLUR.reader.send_socket_active_feeds();
// } else {
// var force_socket = NEWSBLUR.Globals.is_admin;
// NEWSBLUR.reader.setup_socket_realtime_unread_counts(force_socket);
// }
// }, NEWSBLUR.reader));
},
make_social_feeds: function() {
var $social_feeds = this.$s.$social_feeds;
var profile = this.model.user_profile;
$social_feeds.empty();
var $feeds = "";
this.model.social_feeds.sort().each(_.bind(function(feed) {
var $feed = this.make_feed_title_template(feed.attributes, 'feed', 0);
$feeds += $feed;
}, this));
var profile = NEWSBLUR.assets.user_profile;
var $feeds = NEWSBLUR.assets.social_feeds.map(function(feed) {
return new NEWSBLUR.Views.Feed({model: feed, type: 'feed', depth: 0}).render().el;
});
$social_feeds.css({
$social_feeds.empty().css({
'display': 'block',
'opacity': 0
});
$social_feeds.html($feeds);
$social_feeds.animate({'opacity': 1}, {'duration': 700});
if (this.socket) {
this.send_socket_active_feeds();
}
// if (this.socket) {
// this.send_socket_active_feeds();
// }
$('.NB-module-stats-count-shared-stories .NB-module-stats-count-number').text(profile.get('shared_stories_count'));
$('.NB-module-stats-count-followers .NB-module-stats-count-number').text(profile.get('follower_count'));
$('.NB-module-stats-count-following .NB-module-stats-count-number').text(profile.get('following_count'));
},
load_router: function() {
if (!NEWSBLUR.router) {
NEWSBLUR.router = new NEWSBLUR.Router;
var route_found = Backbone.history.start({pushState: true});
this.load_url_next_param(route_found);
}
},
load_url_next_param: function(route_found) {
var next = $.getQueryString('next');
if (next == 'optout') {
NEWSBLUR.reader.open_account_modal({'animate_email': true});
} else if (next == 'goodies') {
NEWSBLUR.reader.open_goodies_modal();
} else if (next == 'password') {
NEWSBLUR.reader.open_account_modal({'change_password': true});
}
var url = $.getQueryString('url');
if (url) {
NEWSBLUR.reader.open_add_feed_modal({url: url});
}
if (!route_found && window.history.replaceState) {
// In case this needs to be found again: window.location.href = BACKBONE
window.history.replaceState({}, null, '/');
}
}
});

View file

@ -1,5 +1,9 @@
NEWSBLUR.Models.Feed = Backbone.Model.extend({
is_social: function() {
return false;
}
});
NEWSBLUR.Collections.Feeds = Backbone.Collection.extend({

View file

@ -1,27 +1,75 @@
NEWSBLUR.Models.FeedOrFolder = Backbone.Model.extend({
initialize: function(model) {
console.log(["constructing model", model]);
if (_.isNumber(model)) {
this.model = NEWSBLUR.assets.feeds.get(model);
} else {
this.model = new NEWSBLUR.Collections.Folders();
this.title = _.keys(model)[0];
var children = model[this.title];
this.model.parse(children);
this.feed = NEWSBLUR.assets.feeds.get(model);
this.set('is_feed', true);
} else if (model) {
var title = _.keys(model)[0];
var children = model[title];
this.set('folder_title', title);
this.folders = new NEWSBLUR.Collections.Folders([], {title: title});
this.folders.parse(children);
}
},
is_feed: function() {
return this.get('is_feed', false);
}
});
NEWSBLUR.Collections.Folders = Backbone.Collection.extend({
options: {
title: ''
},
initialize: function() {
this.comparator = NEWSBLUR.Collections.Folders.comparator;
},
model: NEWSBLUR.Models.FeedOrFolder,
parse: function(models) {
console.log(["parse", this.models, models]);
this.reset(models);
}
}, {
comparator: function(modelA, modelB) {
var sort_order = NEWSBLUR.assets.preference('feed_order');
var feedA, feedB;
if (modelA && modelA.e instanceof jQuery) feedA = NEWSBLUR.assets.feeds.get(parseInt(a.e.data('id'), 10));
if (modelB && modelB.e instanceof jQuery) feedB = NEWSBLUR.assets.feeds.get(parseInt(b.e.data('id'), 10));
if (modelA && modelA.is_feed()) feedA = modelA.model;
if (modelB && modelB.is_feed()) feedB = modelB.model;
// console.log(["feeds", sort_order, modelA, modelB, feedA, feedB]);
if (sort_order == 'ALPHABETICAL' || !sort_order) {
if (feedA && feedB) {
return feedA.get('feed_title').toLowerCase() > feedB.get('feed_title').toLowerCase() ? 1 : -1;
} else if (feedA && !feedB) {
return -1;
} else if (!feedA && feedB) {
return 1;
} else if (!feedA && !feedB && modelA && modelB && !modelA.is_feed() && !modelB.is_feed() && !(modelA.e instanceof jQuery) && !(modelB.e instanceof jQuery)) {
return modelA.get('folder_title').toLowerCase() > modelB.get('folder_title').toLowerCase() ? 1 : -1;
}
} else if (sort_order == 'MOSTUSED') {
if (feedA && feedB) {
return feedA.get('feed_opens') < feedB.get('feed_opens') ? 1 :
(feedA.get('feed_opens') > feedB.get('feed_opens') ? -1 :
(feedA.get('feed_title').toLowerCase() > feedB.get('feed_title').toLowerCase() ? 1 : -1));
} else if (feedA && !feedB) {
return -1;
} else if (!feedA && feedB) {
return 1;
} else if (!feedA && !feedB && modelA && modelB && !modelA.is_feed() && !modelB.is_feed() && !(modelA.e instanceof jQuery) && !(modelB.e instanceof jQuery)) {
return modelA.get('folder_title').toLowerCase() > modelB.get('folder_title').toLowerCase() ? 1 : -1;
}
}
}
});

View file

@ -4,6 +4,10 @@ NEWSBLUR.Models.SocialSubscription = Backbone.Model.extend({
if (!this.get('page_url')) {
this.set('page_url', '/social/page/' + this.get('user_id'));
}
},
is_social: function() {
return true;
}
});

View file

@ -93,7 +93,7 @@
// = Bindings =
// ============
_.bindAll(this, 'show_stories_error', 'make_story_share_comment', 'sort_items');
_.bindAll(this, 'show_stories_error', 'make_story_share_comment');
// ==================
// = Initialization =
@ -109,6 +109,7 @@
if (NEWSBLUR.Flags['start_import_from_google_reader']) {
this.start_import_from_google_reader();
} else {
NEWSBLUR.app.feed_list_header = new NEWSBLUR.Views.FeedListHeader({collection: NEWSBLUR.assets.feeds});
NEWSBLUR.app.feed_list = new NEWSBLUR.Views.FeedList();
}
this.cornerize_buttons();
@ -435,27 +436,6 @@
}
},
load_url_next_param: function(route_found) {
var next = $.getQueryString('next');
if (next == 'optout') {
this.open_account_modal({'animate_email': true});
} else if (next == 'goodies') {
this.open_goodies_modal();
} else if (next == 'password') {
this.open_account_modal({'change_password': true});
}
var url = $.getQueryString('url');
if (url) {
this.open_add_feed_modal({url: url});
}
if (!route_found && window.history.replaceState) {
// In case this needs to be found again: window.location.href = BACKBONE
window.history.replaceState({}, null, '/');
}
},
animate_progress_bar: function($bar, seconds, percentage) {
var self = this;
percentage = percentage || 0;
@ -1117,14 +1097,6 @@
// = Feed Pane =
// =============
load_router: function() {
if (!NEWSBLUR.router) {
NEWSBLUR.router = new NEWSBLUR.Router;
var route_found = Backbone.history.start({pushState: true});
this.load_url_next_param(route_found);
}
},
make_feed_favicons: function() {
var model = this.model;
this.flags['favicons_downloaded'] = true;
@ -1137,103 +1109,11 @@
this.open_dialog_after_feeds_loaded();
},
sort_items: function(a, b) {
var self = this;
var sort_order = this.model.preference('feed_order');
var feedA, feedB;
if (a && a.e instanceof jQuery) feedA = self.model.get_feed(parseInt(a.e.data('id'), 10));
if (b && b.e instanceof jQuery) feedB = self.model.get_feed(parseInt(b.e.data('id'), 10));
if (_.isNumber(a)) feedA = self.model.get_feed(a);
if (_.isNumber(b)) feedB = self.model.get_feed(b);
// console.log(["feeds", sort_order, feedA, feedB]);
if (sort_order == 'ALPHABETICAL' || !sort_order) {
if (feedA && feedB) {
return feedA.feed_title.toLowerCase() > feedB.feed_title.toLowerCase() ? 1 : -1;
} else if (feedA && !feedB) {
return -1;
} else if (!feedA && feedB) {
return 1;
} else if (!feedA && !feedB && a && b && !_.isNumber(a) && !_.isNumber(b) && !(a.e instanceof jQuery) && !(b.e instanceof jQuery)) {
// console.log(['a b 1', a, b, feedA, feedB]);
var folderA = _.keys(a)[0];
var folderB = _.keys(b)[0];
return folderA.toLowerCase() > folderB.toLowerCase() ? 1 : -1;
}
} else if (sort_order == 'MOSTUSED') {
if (feedA && feedB) {
return feedA.feed_opens < feedB.feed_opens ? 1 :
(feedA.feed_opens > feedB.feed_opens ? -1 :
(feedA.feed_title.toLowerCase() > feedB.feed_title.toLowerCase() ? 1 : -1));
} else if (feedA && !feedB) {
return -1;
} else if (!feedA && feedB) {
return 1;
} else if (!feedA && !feedB && a && b && !_.isNumber(a) && !_.isNumber(b) && !(a.e instanceof jQuery) && !(b.e instanceof jQuery)) {
// console.log(['a b 2', a, b]);
var folderA = _.keys(a)[0];
var folderB = _.keys(b)[0];
return folderA.toLowerCase() > folderB.toLowerCase() ? 1 : -1;
}
}
},
sort_feed_models: function(items) {
return items.sort(this.sort_items);
},
sort_feeds: function($feeds) {
$('.feed', $feeds).tsort('', {sortFunction: this.sort_items});
$('.feed', $feeds).tsort('', {sortFunction: NEWSBLUR.Collections.Folders.comparator});
$('.folder', $feeds).tsort('.folder_title_text');
},
make_feeds_folder: function(items, depth, collapsed_parent) {
var self = this;
var $feeds = "";
items = this.sort_feed_models(items);
for (var i in items) {
var item = items[i];
if (typeof item == "number") {
var feed = this.model.get_feed(item);
if (!feed) continue;
var $feed = this.make_feed_title_template(feed, 'feed', depth);
$feeds += $feed;
if (feed.not_yet_fetched && feed.active) {
NEWSBLUR.log(['Feed not fetched', feed]);
this.flags['has_unfetched_feeds'] = true;
}
} else if (typeof item == "object" && item) {
for (var o in item) {
var is_collapsed = _.contains(NEWSBLUR.Preferences.collapsed_folders, o);
var folder = item[o];
var $folder_pre = _.template('\
<li class="folder">\
<div class="folder_title <% if (depth == 0) { %>NB-toplevel<% } %>">\
<div class="NB-folder-icon"></div>\
<div class="NB-feedlist-collapse-icon" title="<% if (is_collapsed) { %>Expand Folder<% } else {%>Collapse Folder<% } %>"></div>\
<div class="NB-feedlist-manage-icon"></div>\
<span class="folder_title_text"><%= folder_title %></span>\
</div>\
<ul class="folder" <% if (is_collapsed) { %>style="display: none"<% } %>>\
', {
depth : depth,
folder_title : o,
is_collapsed : is_collapsed
});
var $folder_post = "</ul></li>";
$feeds += $folder_pre + this.make_feeds_folder(folder, depth+1, is_collapsed) + $folder_post;
}
}
}
$feeds += '<li class="feed NB-empty"></li>';
return $feeds;
},
make_feed_title_template: function(feed, type, depth) {
var unread_class = '';
var exception_class = '';
@ -1311,44 +1191,6 @@
return $feed;
},
make_feed_counts_floater: function(positive_count, neutral_count, negative_count, skip_render) {
var unread_class = "";
if (positive_count) {
unread_class += ' unread_positive';
}
if (neutral_count) {
unread_class += ' unread_neutral';
}
if (negative_count) {
unread_class += ' unread_negative';
}
var $floater = _.template('\
<div class="feed_counts_floater <%= unread_class %>">\
<span class="unread_count unread_count_positive <% if (positive_count) { %>unread_count_full<% } else { %>unread_count_empty<% } %>">\
<%= positive_count %>\
</span>\
<span class="unread_count unread_count_neutral <% if (neutral_count) { %>unread_count_full<% } else { %>unread_count_empty<% } %>">\
<%= neutral_count %>\
</span>\
<span class="unread_count unread_count_negative <% if (negative_count) { %>unread_count_full<% } else { %>unread_count_empty<% } %>">\
<%= negative_count %>\
</span>\
</div>\
', {
positive_count : positive_count,
neutral_count : neutral_count,
negative_count : negative_count,
unread_class : unread_class
});
if (!skip_render) {
$floater = $($floater);
}
return $floater;
},
load_sortable_feeds: function() {
var self = this;
@ -1702,26 +1544,6 @@
this.hide_progress_bar();
},
switch_preferences_hide_read_feeds: function() {
var hide_read_feeds = parseInt(this.model.preference('hide_read_feeds'), 10);
var $button = $('.NB-feeds-header-sites');
if (this.model.preference('show_tooltips')) {
if (hide_read_feeds) {
$button.tipsy('hide');
$button.attr('title', 'Show only unread stories');
$button.tipsy('show');
} else {
$button.tipsy('hide');
$button.attr('title', 'Show all sites');
$button.tipsy('show');
}
}
this.model.preference('hide_read_feeds', hide_read_feeds ? 0 : 1);
this.switch_feed_view_unread_view();
},
// ===============================
// = Feed bar - Individual Feeds =
// ===============================
@ -2012,54 +1834,8 @@
// = Feed Header =
// ===============
count_unreads_across_all_sites: function() {
return _.reduce(this.model.feeds, function(m, v) {
if (v.active) {
m['positive'] += v.ps;
m['neutral'] += v.nt;
m['negative'] += v.ng;
}
return m;
}, {'positive': 0, 'negative': 0, 'neutral': 0});
},
update_header_counts: function(skip_sites, unread_view) {
if (!skip_sites) {
var feeds_count = _.select(this.model.feeds, function(f) {
return f.active;
}).length;
if (feeds_count) {
$('.NB-feeds-header-right .NB-feeds-header-sites').text(feeds_count + Inflector.pluralize(' site', feeds_count));
}
}
var unread_counts = this.count_unreads_across_all_sites();
_(['positive', 'neutral', 'negative']).each(function(level) {
// This is for .NB-feeds-header-count
var $count = $('.NB-feeds-header-'+level);
$count.text(unread_counts[level]);
$count.toggleClass('NB-empty', unread_counts[level] == 0);
});
if (this.model.preference('show_unread_counts_in_title')) {
var title = '(';
var counts = [];
var unread_view = _.isNumber(unread_view) && unread_view || this.model.preference('unread_view');
if (unread_view <= -1) {
counts.push(unread_counts['negative']);
}
if (unread_view <= 0) {
counts.push(unread_counts['neutral']);
}
if (unread_view <= 1) {
counts.push(unread_counts['positive']);
}
if (!unread_counts['negative'] && !unread_counts['positive']) {
counts = [unread_counts['neutral']];
}
title += counts.join('/') + ') NewsBlur';
document.title = title;
}
},
update_starred_count: function() {
@ -6113,7 +5889,6 @@
var unread_view_name = this.get_unread_view_name(unread_view);
var $next_story_button = $('.task_story_next_unread');
var $story_title_indicator = $('.NB-story-title-indicator', this.$story_titles);
var $hidereadfeeds_button = $('.NB-feeds-header-sites');
$feed_list.removeClass('unread_view_positive')
.removeClass('unread_view_neutral')
@ -6123,20 +5898,6 @@
.removeClass('unread_view_neutral')
.removeClass('unread_view_negative')
.addClass('unread_view_'+unread_view_name);
if (NEWSBLUR.Preferences['hide_read_feeds'] == 1) {
$hidereadfeeds_button.attr('title', 'Show all sites');
this.$s.$body.addClass('NB-feedlist-hide-read-feeds');
} else {
$hidereadfeeds_button.attr('title', 'Show only unread stories');
this.$s.$body.removeClass('NB-feedlist-hide-read-feeds');
}
if (this.model.preference('show_tooltips')) {
$hidereadfeeds_button.tipsy({
gravity: 'n',
delayIn: 375
});
}
$next_story_button.removeClass('task_story_next_positive')
.removeClass('task_story_next_neutral')
@ -7891,17 +7652,6 @@
e.preventDefault();
self.show_splash_page();
});
$.targetIs(e, { tagSelector: '.NB-feeds-header-sites' }, function($t, $p){
e.preventDefault();
stopPropagation = true;
self.switch_preferences_hide_read_feeds();
});
if (stopPropagation) return;
$.targetIs(e, { tagSelector: '.NB-feeds-header-dashboard' }, function($t, $p){
e.preventDefault();
self.show_splash_page();
});
$.targetIs(e, { tagSelector: '.NB-intelligence-slider-control' }, function($t, $p){
e.preventDefault();
var unread_value;

View file

@ -1,9 +1,78 @@
NEWSBLUR.Views.Feed = Backbone.View.extend({
className: 'NB-feed',
render: function() {
$(this.el).html(this.make('div', {}, this.model.get('feed_title')));
var feed = this.model;
var unread_class = '';
var exception_class = '';
if (feed.is_social() && !feed.get('feed_title')) {
var profile = NEWSBLUR.assets.user_profiles.get(feed.get('user_id')) || {};
feed.set('feed_title', profile.feed_title);
}
if (feed.get('ps')) {
unread_class += ' unread_positive';
}
if (feed.get('nt')) {
unread_class += ' unread_neutral';
}
if (feed.get('ng')) {
unread_class += ' unread_negative';
}
if (feed.get('has_exception') && feed.get('exception_type') == 'feed') {
exception_class += ' NB-feed-exception';
}
if (feed.get('not_yet_fetched') && !feed.get('has_exception')) {
exception_class += ' NB-feed-unfetched';
}
if (!feed.get('active') && !feed.get('subscription_user_id')) {
exception_class += ' NB-feed-inactive';
}
if (feed.get('subscription_user_id') && !feed.get('shared_stories_count')) {
unread_class += ' NB-feed-inactive';
}
var $feed = _.template('\
<<%= list_type %> class="feed <%= unread_class %> <%= exception_class %> <% if (toplevel) { %>NB-toplevel<% } %>" data-id="<%= feed.id %>">\
<div class="feed_counts">\
<%= feed_counts_floater %>\
</div>\
<img class="feed_favicon" src="<%= $.favicon(feed, empty_on_missing) %>">\
<span class="feed_title">\
<%= feed.get("feed_title") %>\
<% if (type == "story") { %>\
<span class="NB-feedbar-train-feed" title="Train Intelligence"></span>\
<span class="NB-feedbar-statistics" title="Statistics"></span>\
<% } %>\
</span>\
<% if (type == "story") { %>\
<div class="NB-feedbar-last-updated">\
<span class="NB-feedbar-last-updated-label">Updated:</span>\
<span class="NB-feedbar-last-updated-date">\
<% if (feed.get("updated")) { %>\
<%= feed.get("updated") %> ago\
<% } else { %>\
Loading...\
<% } %>\
</span>\
</div>\
<div class="NB-feedbar-mark-feed-read">Mark All as Read</div>\
<% } %>\
<div class="NB-feed-exception-icon"></div>\
<div class="NB-feed-unfetched-icon"></div>\
<div class="NB-feedlist-manage-icon"></div>\
</<%= list_type %>>\
', {
feed : feed,
type : this.options.type,
feed_counts_floater : new NEWSBLUR.Views.FeedCount({model: feed}).render_to_string(),
unread_class : unread_class,
exception_class : exception_class,
toplevel : this.options.depth == 0,
list_type : this.options.type == 'feed' ? 'li' : 'div',
empty_on_missing : !NEWSBLUR.reader.flags['favicons_downloaded'] &&
!NEWSBLUR.reader.flags['showing_feed_in_tryfeed_view'] &&
!NEWSBLUR.reader.flags['showing_social_feed_in_tryfeed_view']
});
this.setElement($feed);
return this;
}

View file

@ -0,0 +1,41 @@
NEWSBLUR.Views.FeedCount = Backbone.View.extend({
render: function() {
$(this.el).html(this.render_to_string());
return this;
},
render_to_string: function() {
var feed = this.model;
var unread_class = "";
if (feed.get('ps')) {
unread_class += ' unread_positive';
}
if (feed.get('nt')) {
unread_class += ' unread_neutral';
}
if (feed.get("ng")) {
unread_class += ' unread_negative';
}
var $floater = _.template('\
<div class="feed_counts_floater <%= unread_class %>">\
<span class="unread_count unread_count_positive <% if (feed.get("ps")) { %>unread_count_full<% } else { %>unread_count_empty<% } %>">\
<%= feed.get("ps") %>\
</span>\
<span class="unread_count unread_count_neutral <% if (feed.get("nt")) { %>unread_count_full<% } else { %>unread_count_empty<% } %>">\
<%= feed.get("nt") %>\
</span>\
<span class="unread_count unread_count_negative <% if (feed.get("ng")) { %>unread_count_full<% } else { %>unread_count_empty<% } %>">\
<%= feed.get("ng") %>\
</span>\
</div>\
', {
feed : feed,
unread_class : unread_class
});
return $floater;
}
});

View file

@ -0,0 +1,130 @@
NEWSBLUR.Views.FeedListHeader = Backbone.View.extend({
events: {
'click .NB-feeds-header-sites' : 'switch_preferences_hide_read_feeds',
'click .NB-feeds-header-dashboard' : 'show_splash_page'
},
initialize: function() {
_.bindAll(this, 'render');
this.collection.bind('reset', this.render);
this.collection.bind('add', this.render);
this.collection.bind('remove', this.render);
this.collection.bind('change', this.render);
var $onpage = $('.NB-feeds-header-dashboard');
this.setElement($onpage);
},
render: function(skip_count) {
if (!skip_count) {
this.count();
}
var hide_read_feeds = parseInt(NEWSBLUR.assets.preference('hide_read_feeds'), 10);
console.log(["render feed list header", this.collection.length, this.feeds_count]);
var $header = _.template('\
<div class="NB-feeds-header-dashboard">\
<div class="NB-feeds-header-right">\
<div class="NB-feeds-header-sites <%= hide_read_feeds ? "NB-feedlist-hide-read-feeds" : "" %>" title="<%= hide_read_feeds ? "Show all sites" : "Show only unread stories" %>"><%= feeds_count %></div>\
</div>\
<div class="NB-feeds-header-left">\
<span class="NB-feeds-header-count NB-feeds-header-negative <% if (!negative_count) { %>NB-empty<% } %>"><%= negative_count %></span>\
<span class="NB-feeds-header-count NB-feeds-header-neutral <% if (!neutral_count) { %>NB-empty<% } %>"><%= neutral_count %></span>\
<span class="NB-feeds-header-count NB-feeds-header-positive <% if (!positive_count) { %>NB-empty<% } %>"><%= positive_count %></span>\
</div>\
<div class="NB-feeds-header-home">Dashboard</div>\
</div>\
', {
feeds_count : (this.feeds_count ? Inflector.pluralize(' site', this.feeds_count, true) : '&nbsp;'),
positive_count : this.unread_counts['positive'],
neutral_count : this.unread_counts['neutral'],
negative_count : this.unread_counts['negative'],
hide_read_feeds : hide_read_feeds
});
$(this.el).html($header);
$("body").toggleClass("NB-feedlist-hide-read-feeds", hide_read_feeds);
if (NEWSBLUR.assets.preference('show_tooltips')) {
this.$('.NB-feeds-header-sites').tipsy({
gravity: 'n',
delayIn: 375
});
}
return this;
},
count: function() {
this.unread_counts = this.count_unreads_across_all_sites();
if (!this.options.skip_sites) {
this.feeds_count = this.count_feeds();
}
if (NEWSBLUR.assets.preference('show_unread_counts_in_title')) {
var title = '(';
var counts = [];
var unread_view = _.isNumber(this.options.unread_view) && this.options.unread_view || NEWSBLUR.assets.preference('unread_view');
if (unread_view <= -1) {
counts.push(this.unread_counts['negative']);
}
if (unread_view <= 0) {
counts.push(this.unread_counts['neutral']);
}
if (unread_view <= 1) {
counts.push(this.unread_counts['positive']);
}
if (!this.unread_counts['negative'] && !this.unread_counts['positive']) {
counts = [this.unread_counts['neutral']];
}
title += counts.join('/') + ') NewsBlur';
document.title = title;
}
},
count_unreads_across_all_sites: function() {
return this.collection.reduce(function(m, v) {
if (v.get('active')) {
m['positive'] += v.get('ps');
m['neutral'] += v.get('nt');
m['negative'] += v.get('ng');
}
return m;
}, {'positive': 0, 'negative': 0, 'neutral': 0});
},
count_feeds: function() {
return this.collection.select(function(f) {
return f.get('active');
}).length;
},
// ==========
// = Events =
// ==========
switch_preferences_hide_read_feeds: function(e) {
e.preventDefault();
e.stopPropagation();
var hide_read_feeds = parseInt(NEWSBLUR.assets.preference('hide_read_feeds'), 10);
NEWSBLUR.assets.preference('hide_read_feeds', hide_read_feeds ? 0 : 1);
if (NEWSBLUR.assets.preference('show_tooltips')) {
var $button = this.$('.NB-feeds-header-sites');
$button.tipsy('hide');
$button.tipsy('disable');
}
this.render(true);
if (NEWSBLUR.assets.preference('show_tooltips')) {
var $button = this.$('.NB-feeds-header-sites');
$button.tipsy('show');
}
},
show_splash_page: function() {
NEWSBLUR.reader.show_splash_page();
}
});

View file

@ -1,25 +1,60 @@
NEWSBLUR.Views.Folder = Backbone.View.extend({
className: 'NB-folder',
className: 'folder',
initialize: function(models) {
this.models = models;
tagName: 'li',
options: {
depth: 0,
collapsed: false,
title: '',
root: false
},
render: function() {
console.log(["render models", this.models]);
var $feeds = _.map(this.models, function(model) {
var depth = this.options.depth;
this.options.collapsed = _.contains(NEWSBLUR.Preferences.collapsed_folders, this.options.title);
var $feeds = this.collection.map(function(item) {
var $model;
console.log(["model", model]);
if (_.isNumber(model)) {
var model = NEWSBLUR.assets.feeds.get(model);
return new NEWSBLUR.Views.Feed({model: model}).render().el;
if (item.is_feed()) {
return new NEWSBLUR.Views.Feed({model: item.feed, type: 'feed', depth: depth}).render().el;
} else {
return new NEWSBLUR.Views.Folder(model).render().el;
return new NEWSBLUR.Views.Folder({
collection: item.folders,
depth: depth + 1,
title: item.get('folder_title')
}).render().el;
}
});
$(this.el).append($feeds);
$feeds.push(this.make('div', { 'class': 'feed NB-empty' }));
var $folder = this.render_folder();
$(this.el).html($folder);
this.$('.folder').append($feeds);
return this;
},
render_folder: function($feeds) {
var $folder = _.template('\
<% if (!root) { %>\
<div class="folder_title <% if (depth == 0) { %>NB-toplevel<% } %>">\
<div class="NB-folder-icon"></div>\
<div class="NB-feedlist-collapse-icon" title="<% if (is_collapsed) { %>Expand Folder<% } else {%>Collapse Folder<% } %>"></div>\
<div class="NB-feedlist-manage-icon"></div>\
<span class="folder_title_text"><%= folder_title %></span>\
</div>\
<% } %>\
<ul class="folder <% if (root) { %>NB-root<% } %>" <% if (is_collapsed) { %>style="display: none"<% } %>>\
</ul>\
', {
depth : this.options.depth,
folder_title : this.options.title,
is_collapsed : this.options.collapsed,
root : this.options.root
});
return $folder;
}
});

View file

@ -421,17 +421,7 @@
<div class="left-pane">
<div class="left-north">
<div class="NB-feeds-header-dashboard">
<div class="NB-feeds-header-right">
<div class="NB-feeds-header-sites">&nbsp;</div>
</div>
<div class="NB-feeds-header-left">
<span class="NB-feeds-header-count NB-feeds-header-negative NB-empty">0</span>
<span class="NB-feeds-header-count NB-feeds-header-neutral NB-empty">0</span>
<span class="NB-feeds-header-count NB-feeds-header-positive NB-empty">0</span>
</div>
<div class="NB-feeds-header-home">Dashboard</div>
</div>
<div class="NB-feeds-header-dashboard"></div>
</div>
<div class="left-center">