changeset 76:1cbd4c5a511b

link the source name to the human URI if available; add a new SnowlFeedSubscriber object that can handle subscribing to feeds from various interfaces and which sets the human URI if available; make the OPML importer use the new SnowlFeedSubscriber object
author Myk Melez <myk@mozilla.org>
date Wed, 14 May 2008 23:22:49 -0700
parents 877a7694445f
children d128eee04c8a
files extension/content/preferences.js extension/modules/feed.js
diffstat 2 files changed, 104 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/extension/content/preferences.js	Wed May 14 22:33:20 2008 -0700
+++ b/extension/content/preferences.js	Wed May 14 23:22:49 2008 -0700
@@ -5,6 +5,8 @@
 
 Cu.import("resource://snowl/modules/service.js");
 Cu.import("resource://snowl/modules/datastore.js");
+Cu.import("resource://snowl/modules/feed.js");
+Cu.import("resource://snowl/modules/URI.js");
 
 let SnowlPreferences = {
   onImportOPML: function() {
@@ -30,18 +32,16 @@
     let outline = xmlDocument.getElementsByTagName("body")[0];
 
     this._importOutline(outline);
-
-    SnowlService.refreshStaleSources();
   },
 
   _importOutline: function(aOutline) {
     // If this outline represents a feed, subscribe the user to the feed.
-    var url = aOutline.getAttribute("xmlUrl");
-    if (url) {
+    let uri = URI.get(aOutline.getAttribute("xmlUrl"));
+    if (uri) {
       // FIXME: make sure the user isn't already subscribed to the feed
       // before subscribing them.
-      let title = aOutline.getAttribute("title") || aOutline.getAttribute("text") || "untitled";
-      this._importItem(url, title);
+      let name = aOutline.getAttribute("title") || aOutline.getAttribute("text") || "untitled";
+      this._importItem(uri, name);
     }
 
     if (aOutline.hasChildNodes()) {
@@ -59,15 +59,7 @@
   },
 
   _importItem: function(aURL, aName) {
-    // FIXME: create the statement once and then reuse it each time.
-    let statement = SnowlDatastore.createStatement("INSERT INTO sources (machineURI, name) VALUES (:machineURI, :name)");
-    try {
-      statement.params.machineURI = aURL;
-      statement.params.name = aName;
-      statement.step();
-    }
-    finally {
-      statement.reset();
-    }
+    let subscriber = new SnowlFeedSubscriber(aURL, aName);
+    subscriber.subscribe();
   }
 };
--- a/extension/modules/feed.js	Wed May 14 22:33:20 2008 -0700
+++ b/extension/modules/feed.js	Wed May 14 23:22:49 2008 -0700
@@ -1,4 +1,4 @@
-EXPORTED_SYMBOLS = ["SnowlFeed"];
+EXPORTED_SYMBOLS = ["SnowlFeed", "SnowlFeedSubscriber"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
@@ -355,3 +355,98 @@
   }
 
 };
+
+// XXX Should we make this part of the Feed object?
+// FIXME: make this accept a callback to which it reports on its progress
+// so we can provide feedback to the user in subscription interfaces.
+function SnowlFeedSubscriber(aURI, aName) {
+  this.uri = aURI;
+  this.name = aName;
+}
+
+SnowlFeedSubscriber.prototype = {
+  uri: null,
+  name: null,
+
+  // Observer Service
+  get _obsSvc() {
+    let obsSvc = Cc["@mozilla.org/observer-service;1"].
+                 getService(Ci.nsIObserverService);
+    delete this._obsSvc;
+    this._obsSvc = obsSvc;
+    return this._obsSvc;
+  },
+
+  QueryInterface: function(aIID) {
+    if (aIID.equals(Ci.nsIDOMEventListener) ||
+        aIID.equals(Ci.nsIFeedResultListener) ||
+        aIID.equals(Ci.nsISupports))
+      return this;
+
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  },
+
+  subscribe: function() {
+    let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
+
+    request = request.QueryInterface(Ci.nsIDOMEventTarget);
+    request.addEventListener("load", this, false);
+    request.addEventListener("error", this, false);
+
+    request = request.QueryInterface(Ci.nsIXMLHttpRequest);
+    request.open("GET", this.uri.spec, true);
+    request.send(null);
+  },
+
+  // nsIDOMEventListener
+
+  handleEvent: function(aEvent) {
+    switch(aEvent.type) {
+      case "load":
+        this.onLoad(aEvent);
+        break;
+      case "error":
+        this.onError(aEvent);
+        break;
+    }
+  },
+
+  onLoad: function(aEvent) {
+    let request = aEvent.target;
+
+    // FIXME: notify the user about the problem.
+    if (request.responseText.length == 0)
+      throw("feed contains no data");
+
+    let parser = Cc["@mozilla.org/feed-processor;1"].
+                 createInstance(Ci.nsIFeedProcessor);
+    parser.listener = this;
+    parser.parseFromString(request.responseText, request.channel.URI);
+  },
+
+  // nsIFeedResultListener
+
+  handleResult: function(aResult) {
+    let feed = aResult.doc.QueryInterface(Components.interfaces.nsIFeed);
+
+    // Subscribe to the feed.
+    let name = this.name || feed.title.plainText();
+    let statement = SnowlDatastore.createStatement("INSERT INTO sources (name, machineURI, humanURI) VALUES (:name, :machineURI, :humanURI)");
+    statement.params.name = name;
+    statement.params.machineURI = this.uri.spec;
+    statement.params.humanURI = feed.link.spec;
+    dump("subscribing to " + name + " <" + this.uri.spec + ">\n");
+    statement.step();
+
+    let id = SnowlDatastore.dbConnection.lastInsertRowID;
+
+    // Now refresh the feed to import all its items.
+    dump("refreshing " + this.uri.spec + "\n");
+    let feed2 = new SnowlFeed(id, this.uri.spec, name);
+    feed2.handleResult(aResult);
+
+    this._obsSvc.notifyObservers(null, "sources:changed", null);
+    this._obsSvc.notifyObservers(null, "messages:changed", null);
+  }
+
+};