Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 332 lines (286 sloc) 9.711 kb
<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="lib/twitter_lib.js"></script>
<script type="text/javascript" src="lib/jquery.base64.js"></script>
<script type="text/javascript" src="lib/oauth.js"></script>
<script type="text/javascript" src="lib/sha1.js"></script>
<script>
TweetManagerConstants = {
MAX_CACHED_ELEMENTS: 30,
WAIT_TIME_UNTIL_REFETCH_HOME: 60 * 1000,
WAIT_TIME_UNTIL_REFETCH_OTHERS: 150 * 1000,
TWEETS_PER_PAGE: 10,
MAX_TWEET_SIZE: 140
};
function TweetsTimeline(timelineId, manager, recheckTime) {
this.timelineId = timelineId;
this.manager = manager;
this.recheckTime = recheckTime;
this.tweetsCache = [];
this.newTweetsCache = [];
this.timerId = null;
this.currentError = null;
this.currentCallback = null;
this.currentScroll = 0;
this.firstRun = true;
this.timelinePath = timelineId;
switch(timelineId) {
case 'home':
this.timelinePath = 'statuses/home_timeline';
break;
case 'mentions':
this.timelinePath = 'statuses/mentions';
break;
case 'dms':
this.timelinePath = 'direct_messages';
break;
}
}
TweetsTimeline.prototype = {
setError: function(status) {
this.currentError = status;
},
stopTimer: function() {
if(this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
},
onFetchNew: function(success, tweets, status, context) {
var _this = this;
if(!success) {
this.setError(status);
if(context.onFinish)
context.onFinish(0);
this.timerId = setTimeout(function() { _this.fetchNewTweets.call(_this); }, this.recheckTime);
return;
}
this.setError(null);
var unreadLength = 0;
for(var i = tweets.length - 1; i >= 0; --i) {
this.newTweetsCache.unshift(tweets[i]);
var tid = tweets[i].id;
if(context.onFinish) {
this.manager.readTweet(tid);
} else if(!this.manager.readTweets[tid]) {
++unreadLength;
this.manager.unreadTweets[tid] = true;
}
}
if(tweets.length > 0) {
this.manager.notifyNewTweets(this.timelineId, this.newTweetsCache.length, unreadLength);
}
if(context.onFinish)
context.onFinish(tweets.length);
this.timerId = setTimeout(function() { _this.fetchNewTweets.call(_this); }, this.recheckTime);
},
fetchNewTweets: function(onFinishCallback) {
this.stopTimer();
var lastId = null;
if(this.newTweetsCache.length > 0) {
lastId = this.newTweetsCache[0].id;
} else if(this.tweetsCache.length > 0) {
lastId = this.tweetsCache[0].id;
}
var _this = this;
var context = { onFinish: onFinishCallback };
this.manager.twitterBackend.timeline(this.timelinePath, function(success, tweets, status, context) {
_this.onFetchNew.call(_this, success, tweets, status, context);
}, context, null, null, lastId);
},
onFetch: function(success, tweets, status, context) {
if(!success) {
this.setError(status);
this.currentCallback(null);
this.setError(null);
this.currentCallback = null;
return;
}
this.setError(null);
var i = 0;
if(context.usingMaxId) {
// If we're fetching using maxId, ignore the first one (we already have it)
i = 1;
}
for(; i < tweets.length; ++i) {
this.tweetsCache.push(tweets[i]);
}
this.currentCallback(this.tweetsCache, this.timelineId);
this.currentCallback = null;
if(this.firstRun) {
this.firstRun = false;
this.fetchNewTweets();
}
},
giveMeTweets: function(callback, syncNew, cacheOnly) {
if(this.currentCallback) {
//Handling multiple calls to giveMeTweets, just update the registered
//callback and let the first request finish.
this.currentCallback = callback;
return;
}
if(syncNew) {
//We should fetch new tweets, update the cache and then return the
//cached results.
var oldNewTweetsCallback = this.manager.newTweetsCallback;
var _this = this;
this.currentCallback = callback;
this.manager.newTweetsCallback = null;
var onFinishCallback = function() {
var tweetsCallback = _this.currentCallback;
_this.currentCallback = null;
_this.updateNewTweets();
_this.manager.updateAlert();
_this.giveMeTweets(tweetsCallback, false, true);
_this.manager.newTweetsCallback = oldNewTweetsCallback;
}
this.fetchNewTweets(onFinishCallback);
return;
}
if(cacheOnly && !this.firstRun) {
//Only return cached results if this is not the first run.
if(this.currentScroll == 0) {
this.cleanUpCache();
}
callback(this.tweetsCache, this.timelineId);
return;
}
//If we didn't return yet it's because we want to fetch old tweets
//from twitter's API.
this.currentCallback = callback;
var maxId = null;
if(this.tweetsCache.length > 0) {
maxId = this.tweetsCache[this.tweetsCache.length - 1].id;
}
var context = {
usingMaxId: !!maxId
}
var _this = this;
this.manager.twitterBackend.timeline(this.timelinePath, function(success, tweets, status, context) {
_this.onFetch.call(_this, success, tweets, status, context);
}, context, TweetManagerConstants.TWEETS_PER_PAGE, null, null, maxId);
},
cleanUpCache: function() {
var len = this.tweetsCache.length;
if(len <= TweetManagerConstants.MAX_CACHED_ELEMENTS)
return;
var i = len - 1;
for(; i >= TweetManagerConstants.MAX_CACHED_ELEMENTS; --i) {
if(!this.manager.isTweetRead(this.tweetsCache[i].id)) {
break;
}
}
this.tweetsCache = this.tweetsCache.slice(0, i + 1);
},
updateNewTweets: function() {
this.tweetsCache = this.newTweetsCache.concat(this.tweetsCache);
this.newTweetsCache = [];
},
newTweetsCount: function() {
var unreadCount = 0;
for(var i = this.newTweetsCache.length - 1; i >= 0; --i) {
if(!this.manager.isTweetRead(this.newTweetsCache[i].id)) {
++unreadCount;
}
}
return [this.newTweetsCache.length, unreadCount];
}
}
function TweetManager() {
this.unreadTweets = {};
this.readTweets = {};
this.newTweetsCallback = null;
this.saveMessage = '';
this.isComposing = false;
this.currentTimeline = "home";
this.timelines = {};
this.timelines["home"] = new TweetsTimeline("home", this, TweetManagerConstants.WAIT_TIME_UNTIL_REFETCH_HOME);
this.timelines["mentions"] = new TweetsTimeline("mentions", this, TweetManagerConstants.WAIT_TIME_UNTIL_REFETCH_OTHERS);
this.timelines["dms"] = new TweetsTimeline("dms", this, TweetManagerConstants.WAIT_TIME_UNTIL_REFETCH_OTHERS);
var _this = this;
this.twitterBackend = new TwitterLib(function onAuthenticated() {
_this.giveMeTweets.call(_this, "home", function() {});
_this.giveMeTweets.call(_this, "mentions", function() {});
_this.giveMeTweets.call(_this, "dms", function() {});
});
}
TweetManager.prototype = {
eachTimeline: function(callback) {
for(var tId in this.timelines) {
callback.call(tId, this.timelines[tId]);
}
},
updateAlert: function() {
var unreadNewCount = 0;
this.eachTimeline(function(timeline) {
unreadNewCount += timeline.newTweetsCount()[1];
});
if(unreadNewCount == 0) {
chrome.browserAction.setTitle({title: "Chromed Bird"});
chrome.browserAction.setIcon({path: 'img/icon19.png'});
chrome.browserAction.setBadgeText({text: ''});
} else {
var title = unreadNewCount + " new tweet";
if(unreadNewCount > 1)
title += "s";
chrome.browserAction.setTitle({title: title});
chrome.browserAction.setIcon({path: 'img/icon19_red.png'});
chrome.browserAction.setBadgeBackgroundColor({color: [255, 0, 0, 0]});
chrome.browserAction.setBadgeText({text: '' + unreadNewCount});
}
},
registerNewTweetsCallback: function(callback) {
this.newTweetsCallback = callback;
},
readTweet: function(id) {
this.readTweets[id] = true;
delete this.unreadTweets[id];
},
isTweetRead: function(id) {
return !this.unreadTweets[id];
},
notifyNewTweets: function(timelineId, size, unreadSize) {
try {
// The callback might be invalid (popup not active), so let's ignore errors for now.
this.newTweetsCallback(size, unreadSize, timelineId);
} catch(e) { /* ignoring */ }
this.updateAlert();
},
postTweet: function(callback, msg, replyId) {
return this.twitterBackend.tweet(callback, msg, replyId);
},
/* Delegates */
giveMeTweets: function(timelineId, callback, syncNew, cacheOnly) {
return this.timelines[timelineId].giveMeTweets(callback, syncNew, cacheOnly);
},
newTweetsCount: function(timelineId) {
return this.timelines[timelineId].newTweetsCount();
},
updateNewTweets: function() {
this.timelines[this.currentTimeline].updateNewTweets();
this.updateAlert();
},
getCurrentTimeline: function() {
return this.timelines[this.currentTimeline];
},
currentError: function() {
return this.timelines[this.currentTimeline].currentError;
},
stopAll: function() {
this.eachTimeline(function(timeline) {
timeline.stopTimer();
delete timeline;
});
},
signout: function() {
localStorage.removeItem('oauth_token_data');
this.stopAll();
TweetManager.instance = new TweetManager();
}
}
TweetManager.instance = new TweetManager();
/* Clean up old versions mess */
localStorage.removeItem('password');
localStorage.removeItem('logged');
localStorage.removeItem('username');
localStorage.removeItem('remember');
</script>
Jump to Line
Something went wrong with that request. Please try again.