mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
Merge branch 'master' of git@github.com:samuelclay/newsblur
This commit is contained in:
commit
620d1af8d7
7 changed files with 362 additions and 13 deletions
1
README
1
README
|
@ -1 +0,0 @@
|
|||
A News/RSS Reader that controls the amount, relevancy, and interestingness of news subscriptions.
|
1
README
Symbolic link
1
README
Symbolic link
|
@ -0,0 +1 @@
|
|||
README.md
|
33
README.md
Executable file
33
README.md
Executable file
|
@ -0,0 +1,33 @@
|
|||
# Objective #
|
||||
|
||||
A News/RSS Reader that controls the amount, relevancy, and interestingness of news subscriptions.
|
||||
|
||||
# Roadmap #
|
||||
|
||||
## version 1.0 ##
|
||||
|
||||
*Spring 2010*
|
||||
|
||||
* Feed management: Adding, removing, sorting/threading, OPML import
|
||||
* Original view: Show the original site and connect stories to rss stories
|
||||
* Feed view: Show all feed entries connected to rss stories
|
||||
* Intelligence: Red/Yellow/Green for Bad/Neutral/Good stories. Based on explicit user preferences.
|
||||
|
||||
## version 1.5 ##
|
||||
|
||||
*Summer 2010*
|
||||
|
||||
* Google Reader import
|
||||
|
||||
## version 2.0 ##
|
||||
|
||||
*Winter 2010*
|
||||
|
||||
* Search
|
||||
* Feed discovery, ala *Give Me Something To Read*
|
||||
|
||||
## version 3.0 ##
|
||||
|
||||
*Spring 2011*
|
||||
|
||||
* Artificial intelligence: implicit behavior creates assumptions about stories
|
|
@ -89,9 +89,14 @@ class UserSubscription(models.Model):
|
|||
def calculate_feed_scores(self):
|
||||
print '[%s]: %s' % (self.feed, self.user)
|
||||
feed_scores = dict(negative=0, neutral=0, positive=0)
|
||||
|
||||
# Two weeks in age. If mark_read_date is older, mark old stories as read.
|
||||
date_delta = datetime.datetime.now()-datetime.timedelta(days=DAYS_OF_UNREAD)
|
||||
if date_delta < self.mark_read_date:
|
||||
date_delta = self.mark_read_date
|
||||
else:
|
||||
self.mark_read_date = date_delta
|
||||
|
||||
read_stories = UserStory.objects.filter(user=self.user,
|
||||
feed=self.feed,
|
||||
story__story_date__gte=date_delta)
|
||||
|
|
282
media/js/jquery.ajaxmanager.3.js
Normal file
282
media/js/jquery.ajaxmanager.3.js
Normal file
|
@ -0,0 +1,282 @@
|
|||
/**!
|
||||
* project-site: http://plugins.jquery.com/project/AjaxManager
|
||||
* repository: http://github.com/aFarkas/Ajaxmanager
|
||||
* @author Alexander Farkas
|
||||
* @version 3.0
|
||||
* Copyright 2010, Alexander Farkas
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*/
|
||||
|
||||
(function($){
|
||||
|
||||
//this can be deleted if jQuery 1.4.2 is out
|
||||
$.support.ajax = !!(window.XMLHttpRequest);
|
||||
if(window.ActiveXObject){
|
||||
try{
|
||||
new ActiveXObject("Microsoft.XMLHTTP");
|
||||
$.support.ajax = true;
|
||||
} catch(e){
|
||||
if(window.XMLHttpRequest){
|
||||
$.ajaxSetup({xhr: function(){
|
||||
return new XMLHttpRequest();
|
||||
}});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var managed = {},
|
||||
cache = {}
|
||||
;
|
||||
$.manageAjax = (function(){
|
||||
function create(name, opts){
|
||||
managed[name] = new $.manageAjax._manager(name, opts);
|
||||
return managed[name];
|
||||
}
|
||||
|
||||
var publicFns = {
|
||||
create: create
|
||||
};
|
||||
|
||||
return publicFns;
|
||||
})();
|
||||
|
||||
$.manageAjax._manager = function(name, opts){
|
||||
this.requests = {};
|
||||
this.inProgress = 0;
|
||||
this.name = name;
|
||||
this.qName = name;
|
||||
|
||||
this.opts = $.extend({}, $.ajaxSettings, $.manageAjax.defaults, opts);
|
||||
if(opts.queue && opts.queue !== true && typeof opts.queue === 'string' && opts.queue !== 'clear'){
|
||||
this.qName = opts.queue;
|
||||
}
|
||||
};
|
||||
|
||||
$.manageAjax._manager.prototype = {
|
||||
add: function(o){
|
||||
o = $.extend({}, this.opts, o);
|
||||
|
||||
var origCom = o.complete,
|
||||
origSuc = o.success,
|
||||
beforeSend = o.beforeSend,
|
||||
origError = o.error,
|
||||
strData = (typeof o.data == 'string') ? o.data : $.param(o.data || {}),
|
||||
xhrID = o.type + o.url + strData,
|
||||
that = this,
|
||||
ajaxFn = this._createAjax(xhrID, o, origSuc, origCom)
|
||||
;
|
||||
|
||||
if(this.requests[xhrID] && o.preventDoubbleRequests){
|
||||
return;
|
||||
}
|
||||
ajaxFn.xhrID = xhrID;
|
||||
o.xhrID = xhrID;
|
||||
|
||||
o.beforeSend = function(xhr, opts){
|
||||
var ret = beforeSend.call(this, xhr, opts);
|
||||
if(ret === false){
|
||||
that._removeXHR(xhrID);
|
||||
}
|
||||
xhr = null;
|
||||
return ret;
|
||||
};
|
||||
o.complete = function(xhr, status){
|
||||
that._complete.call(that, this, origCom, xhr, status, xhrID, o);
|
||||
xhr = null;
|
||||
};
|
||||
|
||||
o.success = function(data, status, xhr){
|
||||
that._success.call(that, this, origSuc, data, status, xhr, o);
|
||||
xhr = null;
|
||||
};
|
||||
|
||||
//always add some error callback
|
||||
o.error = function(ahr, status, errorStr){
|
||||
ahr = (ahr || {});
|
||||
var httpStatus = ahr.status,
|
||||
content = ahr.responseXML || ahr.responseText
|
||||
;
|
||||
if(origError) {
|
||||
origError.call(this, ahr, status, errorStr, o);
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
throw status + ':: status: ' + httpStatus + ' | URL: ' + o.url + ' | data: '+ strData + ' | thrown: '+ errorStr + ' | response: '+ content;
|
||||
}, 0);
|
||||
}
|
||||
ahr = null;
|
||||
};
|
||||
|
||||
if(o.queue === 'clear'){
|
||||
$(document).clearQueue(this.qName);
|
||||
}
|
||||
|
||||
if(o.queue){
|
||||
$.queue(document, this.qName, ajaxFn);
|
||||
if(this.inProgress < o.maxRequests){
|
||||
$.dequeue(document, this.qName);
|
||||
}
|
||||
return xhrID;
|
||||
}
|
||||
return ajaxFn();
|
||||
},
|
||||
_createAjax: function(id, o, origSuc, origCom){
|
||||
var that = this;
|
||||
return function(){
|
||||
if(o.beforeCreate.call(o.context || that, id, o) === false){return;}
|
||||
that.inProgress++;
|
||||
if(o.cacheResponse && cache[id]){
|
||||
that.requests[id] = {};
|
||||
setTimeout(function(){
|
||||
that._complete.call(that, o.context || o, origCom, {}, 'success', id, o);
|
||||
that._success.call(that, o.context || o, origSuc, cache[id], 'success', {}, o);
|
||||
}, 0);
|
||||
} else {
|
||||
that.requests[id] = $.ajax(o);
|
||||
}
|
||||
if(that.inProgress === 1){
|
||||
$.event.trigger(that.name +'AjaxStart');
|
||||
}
|
||||
return id;
|
||||
};
|
||||
},
|
||||
_removeXHR: function(xhrID){
|
||||
if(this.opts.queue){
|
||||
$.dequeue(document, this.qName);
|
||||
}
|
||||
this.inProgress--;
|
||||
this.requests[xhrID] = null;
|
||||
delete this.requests[xhrID];
|
||||
},
|
||||
_isAbort: function(xhr, o){
|
||||
var ret = !!( o.abortIsNoSuccess && ( !xhr || xhr.readyState === 0 || this.lastAbort === o.xhrID ) );
|
||||
xhr = null;
|
||||
return ret;
|
||||
},
|
||||
_complete: function(context, origFn, xhr, status, xhrID, o){
|
||||
if(this._isAbort(xhr, o)){
|
||||
status = 'abort';
|
||||
o.abort.call(context, xhr, status, o);
|
||||
}
|
||||
origFn.call(context, xhr, status, o);
|
||||
|
||||
$.event.trigger(this.name +'AjaxComplete', [xhr, status, o]);
|
||||
|
||||
if(o.domCompleteTrigger){
|
||||
$(o.domCompleteTrigger).trigger(this.name +'DOMComplete', [xhr, status, o]);
|
||||
}
|
||||
|
||||
this._removeXHR(xhrID);
|
||||
if(!this.inProgress){
|
||||
$.event.trigger(this.name +'AjaxStop');
|
||||
}
|
||||
xhr = null;
|
||||
},
|
||||
_success: function(context, origFn, data, status, xhr, o){
|
||||
var that = this;
|
||||
if(this._isAbort(xhr, o)){
|
||||
xhr = null;
|
||||
return;
|
||||
}
|
||||
if(o.abortOld){
|
||||
$.each(this.requests, function(name){
|
||||
if(name === o.xhrID){
|
||||
return false;
|
||||
}
|
||||
that.abort(name);
|
||||
});
|
||||
}
|
||||
if(o.cacheResponse && !cache[o.xhrID]){
|
||||
cache[o.xhrID] = data;
|
||||
}
|
||||
origFn.call(context, data, status, xhr, o);
|
||||
$.event.trigger(this.name +'AjaxSuccess', [xhr, o, data]);
|
||||
if(o.domSuccessTrigger){
|
||||
$(o.domSuccessTrigger).trigger(this.name +'DOMSuccess', [data, o]);
|
||||
}
|
||||
xhr = null;
|
||||
},
|
||||
getData: function(id){
|
||||
if( id ){
|
||||
var ret = this.requests[id];
|
||||
if(!ret && this.opts.queue) {
|
||||
ret = $.grep($(document).queue(this.qName), function(fn, i){
|
||||
return (fn.xhrID === id);
|
||||
})[0];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return {
|
||||
requests: this.requests,
|
||||
queue: (this.opts.queue) ? $(document).queue(this.qName) : [],
|
||||
inProgress: this.inProgress
|
||||
};
|
||||
},
|
||||
abort: function(id){
|
||||
var xhr;
|
||||
if(id){
|
||||
xhr = this.getData(id);
|
||||
|
||||
if(xhr && xhr.abort){
|
||||
this.lastAbort = id;
|
||||
xhr.abort();
|
||||
this.lastAbort = false;
|
||||
} else {
|
||||
$(document).queue(
|
||||
this.qName, $.grep($(document).queue(this.qName), function(fn, i){
|
||||
return (fn !== xhr);
|
||||
})
|
||||
);
|
||||
}
|
||||
xhr = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var that = this,
|
||||
ids = []
|
||||
;
|
||||
$.each(this.requests, function(id){
|
||||
ids.push(id);
|
||||
});
|
||||
$.each(ids, function(i, id){
|
||||
that.abort(id);
|
||||
});
|
||||
},
|
||||
clear: function(shouldAbort){
|
||||
$(document).clearQueue(this.qName);
|
||||
if(shouldAbort){
|
||||
this.abort();
|
||||
}
|
||||
}
|
||||
};
|
||||
$.manageAjax._manager.prototype.getXHR = $.manageAjax._manager.prototype.getData;
|
||||
$.manageAjax.defaults = {
|
||||
complete: $.noop,
|
||||
success: $.noop,
|
||||
beforeSend: $.noop,
|
||||
beforeCreate: $.noop,
|
||||
abort: $.noop,
|
||||
abortIsNoSuccess: true,
|
||||
maxRequests: 1,
|
||||
cacheResponse: false,
|
||||
domCompleteTrigger: false,
|
||||
domSuccessTrigger: false,
|
||||
preventDoubbleRequests: true,
|
||||
queue: false // true, false, clear
|
||||
};
|
||||
|
||||
$.each($.manageAjax._manager.prototype, function(n, fn){
|
||||
if(n.indexOf('_') === 0 || !$.isFunction(fn)){return;}
|
||||
$.manageAjax[n] = function(name, o){
|
||||
if(!managed[name]){
|
||||
if(n === 'add'){
|
||||
$.manageAjax.create(name, o);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
managed[name][n].apply(managed[name], args);
|
||||
};
|
||||
});
|
||||
|
||||
})(jQuery);
|
|
@ -32,11 +32,23 @@ NEWSBLUR.AssetModel.Reader = function() {
|
|||
NEWSBLUR.AssetModel.Reader.prototype = {
|
||||
|
||||
init: function() {
|
||||
this.ajax = {};
|
||||
this.ajax['queue'] = $.manageAjax.create('queue', {queue: false});
|
||||
this.ajax['queue_and_cancel'] = $.manageAjax.create('queue_and_cancel', {queue: 'clear', abortOld: true});
|
||||
return;
|
||||
},
|
||||
|
||||
make_request: function(url, data, callback, error_callback) {
|
||||
$.ajax({
|
||||
make_request: function(url, data, callback, error_callback, options) {
|
||||
var self = this;
|
||||
var options = $.extend({
|
||||
'queue': 'queue'
|
||||
}, options);
|
||||
|
||||
if (options['queue'] == 'queue_and_cancel') {
|
||||
this.ajax[options['queue']].clear(true);
|
||||
}
|
||||
|
||||
this.ajax[options['queue']].add({
|
||||
url: url,
|
||||
data: data,
|
||||
type: 'POST',
|
||||
|
@ -47,15 +59,18 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
success: function(o) {
|
||||
// NEWSBLUR.log(['make_request 1', o]);
|
||||
|
||||
if (callback && typeof callback == 'function'){
|
||||
if ($.isFunction(callback)) {
|
||||
callback(o);
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
NEWSBLUR.log(['AJAX Error', e]);
|
||||
error_callback();
|
||||
// NEWSBLUR.log(['AJAX Error', e]);
|
||||
if ($.isFunction(error_callback)) {
|
||||
error_callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
mark_story_as_read: function(story_id, feed_id, callback) {
|
||||
|
@ -167,7 +182,10 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
feed_id: feed_id,
|
||||
page: page
|
||||
}, pre_callback,
|
||||
error_callback
|
||||
error_callback,
|
||||
{
|
||||
'queue': 'queue_and_cancel'
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -178,7 +196,10 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
{
|
||||
feed_id: feed_id,
|
||||
page: page
|
||||
}, callback
|
||||
}, callback, callback,
|
||||
{
|
||||
'queue': 'queue_and_cancel'
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -567,7 +567,7 @@
|
|||
load_story_feed_view_entry: function(stories, story_index) {
|
||||
var self = this;
|
||||
|
||||
if (stories[story_index]) {
|
||||
if (stories[story_index] && stories[story_index]['story_feed_id'] == this.active_feed) {
|
||||
var story = stories[story_index];
|
||||
var $story = self.cache.feed_view_stories[story.id];
|
||||
|
||||
|
@ -605,6 +605,9 @@
|
|||
|
||||
})($story, story, story_index);
|
||||
}
|
||||
} else if (stories[story_index]
|
||||
&& stories[story_index]['story_feed_id'] != this.active_feed) {
|
||||
NEWSBLUR.log(['Switched off feed early']);
|
||||
} else {
|
||||
NEWSBLUR.log(['Feed view entirely loaded', stories.length + " stories"]);
|
||||
var $feed_view = this.$feed_view;
|
||||
|
@ -674,7 +677,9 @@
|
|||
.bind('click.NB-taskbar', function() {
|
||||
self.taskbar_show_return_to_page();
|
||||
});
|
||||
self.$story_iframe.contents().scroll($.rescope(self.handle_scroll_story_iframe, self));
|
||||
self.$story_iframe.contents()
|
||||
.unbind('scroll')
|
||||
.scroll($.rescope(self.handle_scroll_story_iframe, self));
|
||||
self.prefetch_story_locations_in_story_frame();
|
||||
});
|
||||
},
|
||||
|
@ -948,7 +953,7 @@
|
|||
if (!s) s = 0;
|
||||
var story = stories[s];
|
||||
|
||||
if (story) {
|
||||
if (story && story['story_feed_id'] == this.active_feed) {
|
||||
var self = this;
|
||||
var $story = this.find_story_in_story_iframe(story);
|
||||
// NEWSBLUR.log(['Prefetching story', s, story, $story]);
|
||||
|
@ -969,6 +974,8 @@
|
|||
self.flags.story_frame_prefetched = true;
|
||||
}
|
||||
}, 100);
|
||||
} else if (story && story['story_feed_id'] != this.active_feed) {
|
||||
NEWSBLUR.log(['Switched off iframe early']);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1012,7 +1019,7 @@
|
|||
return $(this).is(':visible');
|
||||
});
|
||||
|
||||
NEWSBLUR.log(['Found stories', $stories, story.story_title]);
|
||||
// NEWSBLUR.log(['Found stories', $stories, story.story_title]);
|
||||
|
||||
var max_size = 0;
|
||||
var $story;
|
||||
|
|
|
@ -177,6 +177,7 @@ COMPRESS_JS = {
|
|||
'js/jquery.hotkeys.js',
|
||||
'js/jquery.dropshadow.js',
|
||||
'js/jquery.ajaxupload.js',
|
||||
'js/jquery.ajaxmanager.3.js',
|
||||
'js/jquery.simplemodal-1.3.js',
|
||||
'js/jquery.color.js',
|
||||
'js/jquery.ui.core.js',
|
||||
|
|
Loading…
Add table
Reference in a new issue