/* Digg Sidebar - Shows Digg stories in the Firefox sidebar in real time. Copyright (C) 2008 Abhinav Sarkar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ var DiggSidebar = { prefs: Application.extensions.get("diggsidebar@abhinavsarkar.net").prefs, storyListRefreshEventTopic: "extension-diggsidebar-abhinavsarkar-net-storylist-refresh", endpoint: { container: null, topic: null, category: "all" }, updateInterval: 10, updateIntervalDecay: 0, shownStoriesCount: 30, categories: ['All', 'Popular', 'Upcoming', 'Hot', 'Top'], timerId: null, storyIds: [], playing: true, stories: [], fetchData: function(url, handler) { DiggSidebar.UI.indicator.style.display = ''; var request = new XMLHttpRequest(); request.onerror = DiggSidebar.errorHandler; request.onload = handler; request.open("GET", url, true); request.send(null); }, errorHandler: function(e) { window.alert("Error in accessing data from Digg"); }, populateMenu: function(e) { var XHR = e.target; var data = DiggSidebar.Utils.decodeJson(XHR.responseText); var topics = data.topics; var containers = new Array(); DiggSidebar.Utils.removeAllChildren(DiggSidebar.UI.topicPopup); topics.forEach(function (topic) { var menu = document.createElement('menu'); menu.setAttribute('id', topic.short_name + 'Menu'); menu.setAttribute('label', topic.name); menu.setAttribute('accesskey', topic.name.charAt(0)); var menupopup = document.createElement('menupopup'); menupopup.setAttribute('id', topic.short_name + 'Popup'); DiggSidebar.categories.forEach( function (label) { var menuitem = document.createElement('menuitem'); menuitem.setAttribute('label', label); menuitem.setAttribute('value', '/topic/' + topic.short_name + '/' + label.toLowerCase()); menuitem.setAttribute('accesskey', label.charAt(0)); menuitem.setAttribute('oncommand', "DiggSidebar.setEndPoint(this.value)"); menupopup.appendChild(menuitem); } ); menu.appendChild(menupopup); DiggSidebar.UI.topicPopup.appendChild(menu); containers.push(topic.container); }); DiggSidebar.Utils.removeAllChildren(DiggSidebar.UI.containerPopup); var filteredContainers = {name: [], short_name: []}; containers.forEach(function (container) { var name = container.name; var short_name = container.short_name; if (filteredContainers.name.indexOf(name) == -1) { filteredContainers.name.push(name); filteredContainers.short_name.push(short_name); } }); for (var i=0; i 0) && (min > 0)) ? (hr + " hr " + min + " mins ago") : ((hr == 0) && (min > 0)) ? (min + " mins ago") : ((hr == 0) && (min == 0)) ? "just now" : ""; var li = DiggSidebar.UI.storyListBox.appendChild(document.createElement('richlistitem')); li.id = "story_" + story.id; var attributes = { title: story.title, date: relativeTime, status: story.status, container: story.container.name, topic: story.topic.name, username: story.user.name, userlink: "http://digg.com/users/" + story.user.name, diggs: story.diggs, comments: story.comments, desc: story.description, link: story.link, href: story.href } for (attr in attributes) li.setAttribute(attr, attributes[attr]); if (DiggSidebar.storyIds.indexOf(story.id) != -1) li.new = false; li.read = story.read; } if (DiggSidebar.storyIds.indexOf(story.id) == -1) newStoryIds.push(story.id); }); DiggSidebar.storyIds = DiggSidebar.storyIds.concat(newStoryIds); DiggSidebar.setUpdateInterval(DiggSidebar.stories.slice(0,5)); window.clearTimeout(DiggSidebar.timerId); var timeout = Math.round(DiggSidebar.updateInterval*(Math.pow(1.5, DiggSidebar.updateIntervalDecay))); DiggSidebar.timerId = window.setTimeout(DiggSidebar.getStories, timeout); DiggSidebar.UI.indicator.style.display = 'none'; }, showDescription: function(storyId) { var jp = new JPath(DiggSidebar.stories); var story = jp.query('//[id == ' + storyId + ']')[0]; story.read = true; var listitems = DiggSidebar.UI.storyListBox.children; for (var i=0; i b[date]) return -1; else if (a[date] < b[date]) return 1; return 0; }); for (var i=0; i 0) { var previousUpdateInterval = DiggSidebar.updateInterval; DiggSidebar.updateInterval = newUpdateInterval; if (previousUpdateInterval == newUpdateInterval) DiggSidebar.updateIntervalDecay += 1; else DiggSidebar.updateIntervalDecay = 0; } //Adaptive update interval code END }, setEndPoint: function(ep) { DiggSidebar.prefs.get("endpoint").value = ep; DiggSidebar.endpoint = DiggSidebar.getEndpointParts(ep); window.clearTimeout(DiggSidebar.timerId); DiggSidebar.getStories(); }, getEndpointParts: function(ep) { var tmp = { topic: null, container: null, category: "all" }; var parts = ep.split("/"); if (parts.length == 2) tmp.category = parts[1]; else if (parts.length == 4) { tmp[parts[1]] = parts[2]; tmp.category = parts[3]; } return tmp; }, togglePlayPause: function() { if (DiggSidebar.playing) { window.clearTimeout(DiggSidebar.timerId); DiggSidebar.UI.playPauseButton.image = "chrome://diggsidebar/content/image/Play.png"; DiggSidebar.UI.playPauseButton.setAttribute("tooltiptext", "Click to Start autoupdate"); DiggSidebar.playing = false; } else { var timeout = Math.round(DiggSidebar.updateInterval*(Math.pow(1.5, DiggSidebar.updateIntervalDecay))); DiggSidebar.timerId = window.setTimeout(DiggSidebar.getStories, timeout); DiggSidebar.UI.playPauseButton.image = "chrome://diggsidebar/content/image/Pause.png"; DiggSidebar.UI.playPauseButton.setAttribute("tooltiptext", "Click to Pause autoupdate"); DiggSidebar.playing = true; } }, initialize: function(){ DiggSidebar.endpoint = DiggSidebar.getEndpointParts(DiggSidebar.prefs.get("endpoint").value); var $ = function(id) {return document.getElementById(id)}; DiggSidebar.UI = {}; DiggSidebar.UI.indicator = $('dsBusyIndicator'); DiggSidebar.UI.topicPopup = $('dsTopicPopup'); DiggSidebar.UI.containerPopup = $('dsContainerPopup'); DiggSidebar.UI.storyListBox = $('dsStoryListBox'); DiggSidebar.UI.endPointDesc = $('dsEndPointDesc'); DiggSidebar.UI.playPauseButton = $('dsPlayPauseButton'); DiggSidebar.storyListObserver = new DiggSidebar.StoryListObserver(); DiggSidebar.createMenu(); DiggSidebar.getStories(); }, destroy: function(){ DiggSidebar.storyListObserver.unregister(); } }; DiggSidebar.Utils = { url: function(spec) { var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); return ios.newURI(spec, null, null); }, openUrlInTab: function(url) { Application.activeWindow.open(DiggSidebar.Utils.url(url)); }, decodeJson: function(string) { var json = Components.classes["@mozilla.org/dom/json;1"] .createInstance(Components.interfaces.nsIJSON); return json.decode(string); }, removeAllChildren: function(node) { while (node.firstChild) node.removeChild(node.firstChild); } } DiggSidebar.StoryListObserver = function() { this.registered = false; this.register(); } DiggSidebar.StoryListObserver.prototype = { observe: function(subject, topic, data) { if (topic == window.DiggSidebar.storyListRefreshEventTopic) { window.DiggSidebar.populateStoryList(); } }, register: function() { if (this.registered == false) { var observerService = Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); observerService.addObserver(this, DiggSidebar.storyListRefreshEventTopic, false); this.registered = true; } }, unregister: function() { if (this.registered == true) { var observerService = Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService); observerService.removeObserver(this, DiggSidebar.storyListRefreshEventTopic); this.registered = false; } } } /*TODO preferences toolbar button refresh button */ /*DONE v0.2 added kdb navigation Added progressmeter added error notification added accesskeys added new story notification v0.2.1 adaptive polling interval promote_date pause/play v0.5 new ui */