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 1000 lines (913 sloc) 29.941 kB
<html>
<head></head>
<body>
<script type="text/javascript" src="lib/3rdparty/jquery.js"></script>
<script type="text/javascript" src="lib/3rdparty/oauth.js"></script>
<script type="text/javascript" src="lib/3rdparty/sha1.js"></script>
<script type="text/javascript" src="lib/twitter_lib.js"></script>
<script type="text/javascript" src="lib/icon_creator.js"></script>
<script>
OptionsBackend = {
defaultOptions: {
home_refresh_interval: 90 * 1000,
mentions_refresh_interval: 150 * 1000,
dms_refresh_interval: 150 * 1000,
lists_refresh_interval: 150 * 1000,
favorites_refresh_interval: 600 * 1000,
tweets_per_page: 10,
max_cached_tweets: 30,
url_shortener: 'bitly',
shortener_acct: false,
shortener_login: '',
shortener_key: '',
name_attribute: 'name',
request_timeout: 6000,
compose_position: 'top',
hover_timeout: 1000,
base_url: 'http://twitter.com/',
base_signing_url: 'http://twitter.com/',
base_authorize_url: 'https://twitter.com/oauth/authorize?oauth_token=',
home_on_page: false,
home_icon: true,
mentions_on_page: true,
mentions_icon: true,
dms_on_page: true,
dms_icon: true,
favorites_on_page: false,
favorites_icon: false,
lists_on_page: true,
lists_icon: true,
home_visible: true,
mentions_visible: true,
dms_visible: true,
favorites_visible: true,
lists_visible: true,
lists_count: 1,
idle_color: '#4880a6',
home_color: '#9c2e2e',
mentions_color: '#7f870b',
dms_color: '#7f870b',
favorites_color: '#7f870b',
lists_color: '#7f870b',
notification_fade_timeout: 6000,
theme: 'css/chromified.css,css/chromified-theme/jquery-ui-1.7.2.custom.css'
},
cachedOptions: null,
save: function(optionsMap) {
localStorage['options'] = JSON.stringify(optionsMap);
this.cachedOptions = this.load();
},
load: function(forceDefault) {
var map = $.extend(true, {}, this.defaultOptions);
if(forceDefault) {
return map;
}
try {
var parsedMap = JSON.parse(localStorage['options']);
if(parsedMap)
$.extend(true, map, parsedMap);
} catch(e) { /* ignored */ }
return map;
},
get: function(option) {
if(this.cachedOptions == null) {
this.cachedOptions = this.load();
}
return this.cachedOptions[option];
}
};
function TweetsTimeline(timelineId, manager, recheckTime) {
this.timelineId = timelineId;
this.manager = manager;
this.recheckTime = recheckTime;
this.tweetsCache = [];
this.newTweetsCache = [];
this.unreadNotified = [];
this.timerId = null;
this.currentError = null;
this.currentCallback = null;
this.currentScroll = 0;
this.firstRun = true;
this.timelinePath = timelineId;
this.usingPages = false;
this.timelineId = timelineId;
this.listId = null;
switch(timelineId) {
case 'home':
this.timelinePath = 'statuses/home_timeline';
break;
case 'mentions':
this.timelinePath = 'statuses/mentions';
break;
case 'dms':
this.timelinePath = 'direct_messages';
break;
case 'favorites':
this.timelinePath = 'favorites';
this.usingPages = true;
break;
}
}
TweetsTimeline.prototype = {
setError: function(status) {
this.currentError = status;
},
setTimelinePath: function(path) {
this.timelinePath = path;
},
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;
if(this.usingPages) {
for(var i = 0; i < tweets.length; ++i) {
var j = 0;
for(; j < this.tweetsCache.length; ++j) {
if(tweets[i].id == this.tweetsCache[j].id) {
break;
}
}
if(j != this.tweetsCache.length) {
break;
}
this.newTweetsCache.push(tweets[i]);
}
} else {
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 };
var params = {};
if(this.usingPages) {
//No params
} else {
if(lastId) {
params.since_id = lastId;
}
}
this.manager.twitterBackend.timeline(this.timelinePath, function(success, tweets, status, context) {
_this.onFetchNew.call(_this, success, tweets, status, context);
}, context, params);
},
onFetch: function(success, tweets, status, context) {
if(!success) {
this.setError(status);
this.currentCallback(null);
this.setError(null);
this.currentCallback = null;
return;
}
this.setError(null);
if(this.usingPages) {
for(var i = 0; i < tweets.length; ++i) {
this.pushTweet(tweets[i]);
}
} else {
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;
var _this = this;
this.timerId = setTimeout(function() { _this.fetchNewTweets.call(_this); }, this.recheckTime);
}
},
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 _this = this;
var params, context;
if(this.usingPages) {
params = {page: (this.tweetsCache.length / 20) + 1};
} else {
var maxId = null;
if(this.tweetsCache.length > 0) {
maxId = this.tweetsCache[this.tweetsCache.length - 1].id;
}
context = {
usingMaxId: !!maxId
}
params = {count: OptionsBackend.get('tweets_per_page'), per_page: OptionsBackend.get('tweets_per_page')};
if(maxId) {
params.max_id = maxId;
}
}
this.manager.twitterBackend.timeline(this.timelinePath, function(success, tweets, status, context) {
_this.onFetch.call(_this, success, tweets, status, context);
}, context, params);
},
cleanUpCache: function() {
var len = this.tweetsCache.length;
if(len <= OptionsBackend.get('max_cached_tweets'))
return;
this.tweetsCache = this.tweetsCache.slice(0, OptionsBackend.get('max_cached_tweets') + 1);
},
updateNewTweets: function() {
this.tweetsCache = this.newTweetsCache.concat(this.tweetsCache);
this.newTweetsCache = [];
this.unreadNotified = [];
},
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];
},
getNewUnreadTweets: function() {
var unreadNewList = [];
for(var i = 0; i < this.newTweetsCache.length; ++i) {
if(!this.manager.isTweetRead(this.newTweetsCache[i].id) && !this.unreadNotified[this.newTweetsCache[i].id]) {
unreadNewList.push(this.newTweetsCache[i]);
this.unreadNotified[this.newTweetsCache[i].id] = true;
}
}
return unreadNewList;
},
getNewUnreadIds: function() {
var unreadNewIds = [];
for(var i = 0; i < this.newTweetsCache.length; ++i) {
if(!this.manager.isTweetRead(this.newTweetsCache[i].id)) {
unreadNewIds.push(this.newTweetsCache[i].id);
}
}
return unreadNewIds;
},
removeFromCache: function(id) {
var i = 0;
for(; i < this.tweetsCache.length; ++i) {
if(this.tweetsCache[i].id == id)
break;
}
if(i != this.tweetsCache.length) {
this.tweetsCache.splice(i, 1);
}
},
findTweet: function(id) {
var i = 0;
for(; i < this.tweetsCache.length; ++i) {
if(this.tweetsCache[i].id == id)
return this.tweetsCache[i];
}
return null;
},
pushTweet: function(tweet) {
var baseTime = Date.parse(tweet.created_at);
var i = 0;
for(; i < this.tweetsCache.length; ++i) {
var tweetTime = Date.parse(this.tweetsCache[i].created_at);
if(baseTime >= tweetTime) {
break;
}
}
if(i == this.tweetsCache.length || this.tweetsCache[i].id != tweet.id)
this.tweetsCache.splice(i, 0, tweet);
}
}
function ComposerData() {
this.saveMessage = '';
this.urlShortener = '';
this.isComposing = false;
this.replyId = null;
this.replyUser = null;
}
function TweetManager() {
this.unreadTweets = {};
this.readTweets = {};
this.retweets = {};
this.injectTweets = null;
this.newTweetsCallback = null;
this.composerData = new ComposerData();
this.timelines = {};
this.iconImg = null;
this.listsCache = null;
this.listsTabCount = OptionsBackend.get('lists_count');
this.loadIcon();
var timelineNames = ["home", "mentions", "dms", "favorites", "lists"];
for(var i = 0; i < timelineNames.length; ++i) {
var refreshInterval = OptionsBackend.get(timelineNames[i] + '_refresh_interval');
var visible = OptionsBackend.get(timelineNames[i] + '_visible');
if(!visible) {
continue;
}
if(timelineNames[i] == "lists") {
for(var j = 0; j < this.listsTabCount; ++j) {
this.timelines["lists_" + j] = new TweetsTimeline("lists_" + j, this, refreshInterval);
}
} else {
this.timelines[timelineNames[i]] = new TweetsTimeline(timelineNames[i], this, refreshInterval);
}
if(!this.currentTimeline) {
this.currentTimeline = (timelineNames[i] == "lists") ? "lists_0" : timelineNames[i];
}
}
this.lastAvailableHits = null;
this.lastAvailableHitsTime = null;
this.warningsCallback = null;
this.warningMessage = null;
this.autoClearWarning = false;
this.tooManyHitsCount = 0;
var _this = this;
this.twitterBackend = new TwitterLib(OptionsBackend.get('request_timeout'),
function onAuthenticated() {
for(var i = 0; i < timelineNames.length; ++i) {
var visible = OptionsBackend.get(timelineNames[i] + '_visible');
if(!visible) {
continue;
}
if(timelineNames[i] == "lists") {
_this.lists();
var selectedLists = _this.getSelectedLists();
for(var timelineId in selectedLists) {
var timeline = _this.changeList(timelineId, selectedLists[timelineId]);
if(timeline) {
timeline.giveMeTweets(function() {});
}
}
} else {
_this.giveMeTweets.call(_this, timelineNames[i], function() {});
}
}
},
function(remainingHits, nextHitsReset, hourlyLimit) {
_this.onHitsUpdated.call(_this, remainingHits, nextHitsReset, hourlyLimit);
},
OptionsBackend.get('base_url'),
OptionsBackend.get('base_authorize_url'),
OptionsBackend.get('base_signing_url')
);
}
TweetManager.prototype = {
setWarning: function(msg) {
this.warningMessage = msg;
try {
if(this.warningCallback) {
this.warningCallback(msg);
}
} catch(e) {
/* ignoring, the popup window might be closed. */
}
},
clearWarning: function() {
this.warningMessage = null;
},
registerWarningsCallback: function(callback) {
this.warningsCallback = callback;
if(this.warningMessage && this.warningsCallback) {
this.warningsCallback(this.warningMessage);
}
},
getSelectedLists: function() {
var selectedListsStr = localStorage['selected_lists']
if(selectedListsStr) {
return JSON.parse(selectedListsStr);
}
return {};
},
registerSelectedList: function(timelineId, listId) {
var selectedLists = this.getSelectedLists();
selectedLists[timelineId] = listId;
localStorage['selected_lists'] = JSON.stringify(selectedLists);
},
eachTimeline: function(callback) {
for(var tId in this.timelines) {
callback.call(tId, this.timelines[tId]);
}
},
orderedEachTimeline: function(callback) {
var retList = [];
for(var tId in this.timelines) {
var orderedPos = this.getTimelinePosition(tId);
if(orderedPos == -1) {
orderedPos = retList.length;
}
if(retList[orderedPos]) {
retList.splice(orderedPos, 0, tId);
} else {
retList[orderedPos] = tId;
}
}
for(var i = 0; i < retList.length; ++i) {
var tId = retList[i];
if(tId) {
callback.call(tId, this.timelines[tId]);
}
}
},
getTimelinePosition: function(timelineId) {
if(!this.timelineOrderCache) {
var storedOrder = localStorage['timeline_order'];
if(storedOrder) {
this.timelineOrderCache = JSON.parse(storedOrder);
} else {
this.timelineOrderCache = [];
}
}
for(var i = 0; i < this.timelineOrderCache.length; ++i) {
if(timelineId == this.timelineOrderCache[i]) {
return i;
}
}
return -1;
},
setTimelineOrder: function(sortedTimelinesArray) {
this.timelineOrderCache = sortedTimelinesArray;
localStorage['timeline_order'] = JSON.stringify(sortedTimelinesArray);
},
loadIcon: function() {
var $icon = $('<img>').attr('src', 'img/icon19.png');
$icon.load(function() {
chrome.browserAction.setIcon({imageData: IconCreator.paintIcon(this, OptionsBackend.get('idle_color'))});
});
this.iconImg = $icon[0];
},
unique: function(srcList) {
var newList = [];
for(var i = 0; i < srcList.length; ++i) {
if($.inArray(srcList[i], newList) == -1) {
newList[newList.length] = srcList[i];
}
}
return newList;
},
updateAlert: function() {
var colors = [];
var unreadNewTweets = [];
var totalUnreadNewIds = [];
this.eachTimeline(function(timeline) {
var timelineId = this;
var unreadNewIds = timeline.getNewUnreadIds();
totalUnreadNewIds = totalUnreadNewIds.concat(unreadNewIds);
if(unreadNewIds.length > 0) {
if(timelineId.match(/^lists/)) {
timelineId = 'lists';
}
if(OptionsBackend.get(timelineId + '_icon')) {
colors.push(OptionsBackend.get(timelineId + '_color'));
}
if(OptionsBackend.get(timelineId + '_on_page')) {
unreadNewTweets = unreadNewTweets.concat(timeline.getNewUnreadTweets());
}
}
});
var totalUnreadNewCount = this.unique(totalUnreadNewIds).length;
if(colors.length == 0) {
chrome.browserAction.setTitle({title: "Chromed Bird"});
chrome.browserAction.setIcon({imageData: IconCreator.paintIcon(this.iconImg, OptionsBackend.get('idle_color'))});
chrome.browserAction.setBadgeText({text: ''});
} else {
var title = totalUnreadNewCount + " new tweet";
if(totalUnreadNewCount > 1)
title += "s";
chrome.browserAction.setTitle({title: title});
chrome.browserAction.setIcon({imageData: IconCreator.paintIcon(this.iconImg, colors)});
chrome.browserAction.setBadgeBackgroundColor({color: [255, 0, 0, 0]});
chrome.browserAction.setBadgeText({text: '' + totalUnreadNewCount});
}
if(unreadNewTweets.length > 0) {
this.injectTweets = unreadNewTweets;
var injectHelper = function(action, file, allFrames, callback) {
var method;
if(action == 'script') {
method = chrome.tabs.executeScript;
} else if(action == 'css') {
method = chrome.tabs.insertCSS;
} else {
return;
}
var params = {file: file};
if(allFrames) {
params.allFrames = true;
}
try {
method.call(chrome.tabs, null, params, callback);
} catch(e) {
// Maybe this exception is due to allFrames = true, let's try without it
if(allFrames) {
try {
method.call(chrome.tabs, null, {file: file}, callback);
} catch(e) {
// This time something really bad happened, logging and ignoring
console.log(e);
}
} else {
// We don't know the motive, logging and ignoring
console.log(e);
}
}
};
injectHelper('script', 'lib/3rdparty/jquery.js', true, function() {
injectHelper('css', 'css/injectedTweets.css', true, function() {
injectHelper('script', 'lib/tweets_assembler.js', true);
});
});
}
},
registerNewTweetsCallback: function(callback) {
this.newTweetsCallback = callback;
},
readTweet: function(id) {
this.readTweets[id] = true;
delete this.unreadTweets[id];
var _this = this;
this.eachTimeline(function(timeline) {
var newTweets = timeline.newTweetsCount();
_this.notifyNewTweets(this, newTweets[0], newTweets[1]);
});
},
isTweetRead: function(id) {
return !this.unreadTweets[id];
},
isRetweet: function(id) {
return this.retweets[id];
},
notifyNewTweets: function(timelineId, size, unreadSize) {
try {
// The callback might be invalid (popup not active), so let's ignore errors for now.
if(this.newTweetsCallback) {
this.newTweetsCallback(size, unreadSize, timelineId);
}
} catch(e) { /* ignoring */ }
this.updateAlert();
},
postTweet: function(callback, msg, replyId) {
return this.twitterBackend.tweet(callback, msg, replyId);
},
postRetweet: function(callback, id) {
var _this = this;
return this.twitterBackend.retweet(function(success, data, status) {
if(success) {
_this.retweets[id] = true;
}
callback(success, data, status);
}, id);
},
destroy: function(callback, id) {
var _this = this;
var firstCallback = function(success, data, status) {
if(success) {
_this.eachTimeline(function(timeline) {
timeline.removeFromCache(id);
});
}
callback(success, data, status);
};
if(this.currentTimeline == "dms") {
return this.twitterBackend.destroyDM(firstCallback, id);
} else {
return this.twitterBackend.destroy(firstCallback, id);
}
},
favorite: function(callback, id) {
var _this = this;
var firstCallback = function(success, data, status) {
if(success) {
var favTimeline = _this.timelines["favorites"];
favTimeline.pushTweet(data);
_this.eachTimeline(function(timeline) {
var tweet = timeline.findTweet(id);
if(tweet)
tweet.favorited = true;
});
}
callback(success, data, status);
};
return this.twitterBackend.favorite(firstCallback, id);
},
unFavorite: function(callback, id) {
var _this = this;
var firstCallback = function(success, data, status) {
if(success) {
var favTimeline = _this.timelines["favorites"];
favTimeline.removeFromCache(id);
_this.eachTimeline(function(timeline) {
var tweet = timeline.findTweet(id);
if(tweet)
tweet.favorited = false;
});
}
callback(success, data, status);
};
return this.twitterBackend.unFavorite(firstCallback, id);
},
lists: function(force, callback) {
if(force) {
this.listsCache = null;
}
if(!this.listsCache) {
var _this = this;
this.twitterBackend.lists(function(success, data, status) {
if(success) {
_this.listsCache = data.lists;
}
if(callback) {
callback(success, _this.listsCache, status);
}
});
return;
}
if(callback) {
callback(true, this.listsCache, null);
}
},
changeList: function(timelineName, listId) {
var timeline = this.timelines[timelineName];
if(!timeline) {
return null;
}
if(timeline.listId != listId) {
this.registerSelectedList(timelineName, listId);
timeline.stopTimer();
delete this.timelines[timelineName];
timeline = this.timelines[timelineName] = new TweetsTimeline(timelineName, this, OptionsBackend.get('lists_refresh_interval'));
}
timeline.listId = listId;
timeline.setTimelinePath(this.twitterBackend.username() + '/lists/' + listId + '/statuses');
return timeline;
},
getListId: function(timelineName) {
if(!timelineName) {
timelineName = this.currentTimeline;
}
var timeline = this.timelines[timelineName];
if(!timeline) {
return null;
}
var listId = timeline.listId;
if(listId && this.listsCache) {
for(var i = 0; i < this.listsCache.length; ++i) {
if(this.listsCache[i].slug == listId) {
return listId;
}
}
}
return null;
},
/* Delegates */
giveMeTweets: function(timelineId, callback, syncNew, cacheOnly) {
var timeline = this.timelines[timelineId];
if(!timeline) {
callback([], timelineId);
return;
}
return timeline.giveMeTweets(callback, syncNew, cacheOnly);
},
newTweetsCount: function(timelineId) {
return this.timelines[timelineId].newTweetsCount();
},
updateNewTweets: function() {
if(this.currentTimeline == 'favorites') {
for(var i = 0, len = this.timelines[this.currentTimeline].newTweetsCache.length; i < len; ++i) {
var id = this.timelines[this.currentTimeline].newTweetsCache[i].id;
this.eachTimeline(function(timeline) {
var tweet = timeline.findTweet(id);
if(tweet)
tweet.favorited = true;
});
}
}
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');
localStorage.removeItem('selected_lists');
this.stopAll();
TweetManager.instance = new TweetManager();
},
markTimelineAsRead: function() {
var tweetsToRead = this.getCurrentTimeline().tweetsCache;
for(var i = 0; i < tweetsToRead.length; ++i) {
this.readTweet(tweetsToRead[i].id);
}
},
onHitsUpdated: function(remainingHits, nextHitsReset, hourlyLimit) {
var nextResetDate = new Date();
nextResetDate.setTime(parseInt(nextHitsReset) * 1000);
if(remainingHits == 0) {
this.autoClearWarning = true;
this.setWarning("You've exceeded API hits limit. " +
"Please review your refresh interval settings in the <a href='javascript:chrome.tabs.create({url:\"" + chrome.extension.getURL('options.html') + "\"})'>options page</a>. " +
"Chromed Bird won't update until " + nextResetDate.toLocaleDateString() + " " + nextResetDate.toLocaleTimeString() + ".");
return;
}
if(this.autoClearWarning) {
this.autoClearWarning = false;
this.clearWarning();
}
if(this.lastAvailableHitsTime == null) {
this.lastAvailableHitsTime = new Date();
this.lastAvailableHits = remainingHits;
}
var timeDiff = new Date() - this.lastAvailableHitsTime;
if(timeDiff >= 5 * 60 * 1000) {
var realHitsPerHour = ((this.lastAvailableHits - remainingHits) / timeDiff) * 60 * 60 * 1000;
if(realHitsPerHour > hourlyLimit) {
// If we keep this same speed we're gonna exhaust our hits limit.
this.tooManyHitsCount += 1;
if(this.tooManyHitsCount >= 2) {
// We've exceeded the limit twice in a row, let's warn users.
this.setWarning("Hey! Your remaining API hits are ending too fast.<br>" +
"Please review your refresh interval settings in the <a href='javascript:chrome.tabs.create({url:\"" + chrome.extension.getURL('options.html') + "\"})'>options page</a>. " +
"Take special care if you're running multiple Twitter clients, as they all share the same limit.<br>" +
"Available hits left: " + remainingHits + " - Next hits reset: " + nextResetDate.toLocaleDateString() + " " + nextResetDate.toLocaleTimeString());
this.tooManyHitsCount = 0;
}
} else {
// We only wanna warn users if we exceed hits limit more than once
// in a row, so let's just reset the counter.
this.tooManyHitsCount = 0;
}
this.lastAvailableHitsTime = new Date();
this.lastAvailableHits = remainingHits;
}
}
}
/* Clean up old versions mess */
localStorage.removeItem('password');
localStorage.removeItem('logged');
localStorage.removeItem('username');
localStorage.removeItem('remember');
localStorage.removeItem('currentTheme');
function compareVersions(v1, v2) {
if(!v1) return -1;
if(!v2) return 1;
var maxLen = Math.max(v1.length, v2.length);
for(var i = 0; i < maxLen; ++i) {
if(!v1[i]) return -1;
if(!v2[i]) return 1;
if(v1[i] > v2[i]) return 1;
if(v1[i] < v2[i]) return -1;
}
return 0;
}
function checkVersionChanges(manifest) {
try {
var currentVersion = manifest.version.split('.');
var storageVersion = localStorage['version'];
if(storageVersion) {
storageVersion = JSON.parse(storageVersion);
}
if(compareVersions(currentVersion, storageVersion) != 0) {
// if last version is < 1.3.0
if(compareVersions(storageVersion, [1, 3, 0]) < 0) {
//Old default refresh interval, let's update it for the new version
if(OptionsBackend.get('home_refresh_interval') == 60000) {
var options = OptionsBackend.load();
options['home_refresh_interval'] = OptionsBackend.defaultOptions['home_refresh_interval'];
OptionsBackend.save(options);
}
}
//TODO: Maybe restart tweetManager
localStorage['version'] = JSON.stringify(currentVersion);
}
} catch(e) {
/* experimental code, something can go wrong */
console.log(e);
}
}
initializeExtension();
$.ajax({
type: 'GET',
url: 'manifest.json',
data: {},
dataType: "json",
timeout: 5000,
success: function(data, status) {
checkVersionChanges(data);
},
error: function (request, status, error) {
try {
// Ugly hack, but currently Chrome is returning an error
checkVersionChanges(JSON.parse(request.responseText));
} catch(e) {
/* Something can go wrong, ignoring... */
}
}
});
function initializeExtension() {
TweetManager.instance = new TweetManager();
var waitingFirstRequest = true;
var selectedResponse = null;
var biggestArea = -1;
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.cb_requesting_tweets) {
if(waitingFirstRequest) {
waitingFirstRequest = false;
setTimeout(function() {
if(selectedResponse) {
selectedResponse({
tweets: TweetManager.instance.injectTweets,
nameAttribute: OptionsBackend.get('name_attribute'),
extensionId: location.host,
fadeTimeout: OptionsBackend.get('notification_fade_timeout')
});
}
waitingFirstRequest = true;
TweetManager.instance.injectTweets = null;
biggestArea = -1;
}, 200);
}
var area = request.frame_area;
if(area >= biggestArea) {
biggestArea = area;
selectedResponse = sendResponse;
}
}
});
}
</script>
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.