/* Digg Sidebar - Shows Digg stories in the Firefox sidebar in real time. Copyright (C) 2008 Abhinav Sarkar This file is a part of Digg Sidebar. Digg Sidebar 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. Digg Sidebar 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 Digg Sidebar. If not, see . */ var DiggSidebar = { homepageURL: "http://code.google.com/p/digg-sidebar/", prefs: Application.extensions.get("diggsidebar@abhinavsarkar.net").prefs, storyListRefreshEventTopic: "extension-diggsidebar-abhinavsarkar-net-storylist-refresh", endpoint: { container: null, topic: null, category: "all" }, updateInterval: 1000, updateIntervalDecay: 0, lastUpdateAt: new Date().getTime(), shownStoriesCount: 30, categories: ['All', 'Popular', 'Upcoming', 'Hot', 'Top'], timerId: null, storyIds: [], refreshing: false, stories: [], expandedStory: null, fetchData: function(url, handler) { DiggSidebar.indicateActivity(); var request = new XMLHttpRequest(); request.onerror = DiggSidebar.errorHandler; request.onload = handler; request.open("GET", url, true); request.send(null); }, errorHandler: function(e) { /*if (DiggSidebar.UI.notificationBox.allNotifications.length > 0) DiggSidebar.UI.notificationBox.removeAllNotifications(true);*/ DiggSidebar.UI.notificationBox.appendNotification( "Unable to access Digg", "dsAccessFailNotification", null, "PRIORITY_CRITICAL_HIGH", [{callback:DiggSidebar.getStories, label: "Retry", accessKey: "R"}] ); DiggSidebar.refreshing = false; DiggSidebar.indicateInactivity(); }, populateMenu: function(e) { var XHR = e.target; var data = DiggSidebar.Utils.decodeJson(XHR.responseText); var containers = data.containers; containers.forEach(function (container) { var cmenu = document.createElement('menu'); cmenu.setAttribute('id', container.short_name + 'Menu'); cmenu.setAttribute('label', container.name); cmenu.setAttribute('accesskey', container.name.charAt(0)); var cmenupopup = document.createElement('menupopup'); cmenupopup.setAttribute('id', container.short_name + 'Popup'); DiggSidebar.categories.forEach( function (category) { var cmenuitem = document.createElement('menuitem'); cmenuitem.setAttribute('label', category); cmenuitem.setAttribute('value', '/container/' + container.short_name + '/' + category.toLowerCase()); cmenuitem.setAttribute('accesskey', category.charAt(0)); cmenuitem.setAttribute('oncommand', "DiggSidebar.setEndPoint(this.value)"); cmenupopup.appendChild(cmenuitem); } ); cmenupopup.appendChild(document.createElement('menuseparator')); var topics = container.topics; topics.forEach(function (topic) { var tmenu = document.createElement('menu'); tmenu.setAttribute('id', topic.short_name + 'Menu'); tmenu.setAttribute('label', topic.name); tmenu.setAttribute('accesskey', topic.name.charAt(0)); var tmenupopup = document.createElement('menupopup'); tmenupopup.setAttribute('id', topic.short_name + 'Popup'); DiggSidebar.categories.forEach( function (category) { var tmenuitem = document.createElement('menuitem'); tmenuitem.setAttribute('label', category); tmenuitem.setAttribute('value', '/topic/' + topic.short_name + '/' + category.toLowerCase()); tmenuitem.setAttribute('accesskey', category.charAt(0)); tmenuitem.setAttribute('oncommand', "DiggSidebar.setEndPoint(this.value)"); tmenupopup.appendChild(tmenuitem); } ); tmenu.appendChild(tmenupopup); cmenupopup.appendChild(tmenu); }); cmenu.appendChild(cmenupopup); DiggSidebar.UI.storiesPopup.appendChild(cmenu); }); }, populateStoryList: function() { var newStoryIds = new Array(); var jp = new JPath(DiggSidebar.stories); var filteredStories = jp.$(function(story){ return (story.$("category").json == DiggSidebar.endpoint.category) ; }).json; jp = new JPath(filteredStories); if (DiggSidebar.endpoint.topic) filteredStories = jp.$(function(story){ return (story.$("topic/short_name").json == DiggSidebar.endpoint.topic); }).json; if (DiggSidebar.endpoint.container) filteredStories = jp.$(function(story){ return story.$("container/short_name").json == DiggSidebar.endpoint.container; }).json; if (filteredStories.length > 0) DiggSidebar.Utils.removeAllChildren(DiggSidebar.UI.storyListBox); filteredStories.forEach(function (story, index) { if (index < DiggSidebar.shownStoriesCount) { var now = new Date(); if (story.promote_date != null) var then = new Date(story.promote_date*1000); else var then = new Date(story.submit_date*1000); var diff = Math.max(now - then, 0) var hr = Math.floor(diff/(1000*3600)); var min = Math.floor(diff/(1000*60)) - 60*hr; var relativeTime = ((hr > 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 (var attr in attributes) li.setAttribute(attr, attributes[attr]); li.read = story.read; if (story.id == DiggSidebar.expandedStory) li.showDescription(); } if (DiggSidebar.storyIds.indexOf(story.id) == -1) newStoryIds.push(story.id); }); DiggSidebar.storyIds = DiggSidebar.storyIds.concat(newStoryIds); }, showDescription: function(storyId) { var jp = new JPath(DiggSidebar.stories); var story = jp.query('//[id == ' + storyId + ']')[0]; story.read = true; DiggSidebar.expandedStory = parseInt(storyId); var listitems = DiggSidebar.UI.storyListBox.children; for (var i=0; i 3600) ? Math.round(autoRefreshTime/3600) + " hours": (autoRefreshTime > 60) ? Math.round(autoRefreshTime/60) + " minutes": autoRefreshTime + " seconds"; setAttribute('tooltiptext', "Click to refresh now.\n" + "Autorefreshing in " + autoRefreshTime); } } DiggSidebar.lastUpdateAt = new Date().getTime(); }, initialize: function(){ DiggSidebar.endpoint = DiggSidebar.getEndpointParts(DiggSidebar.prefs.get("endpoint").value); var $ = function(id) {return document.getElementById(id)}; DiggSidebar.UI = {}; DiggSidebar.UI.notificationBox = $('dsNotificationBox'); DiggSidebar.UI.indicator = $('dsBusyIndicator'); DiggSidebar.UI.storiesPopup = $('dsStoriesPopup'); DiggSidebar.UI.storyListBox = $('dsStoryListBox'); DiggSidebar.UI.endPointDesc = $('dsEndPointDesc'); 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; } } } /*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 v0.7 moved to JSON data format moved HTML template to XBL refactored JavaScript/Using FUEL implemented caching and notifier-observer new UI added toolbar button put license */