changeset 51:7938fd5e956a

first version of river of news view that works
author Myk Melez <myk@mozilla.org>
date Wed, 07 May 2008 13:45:18 -0700
parents f83981ab4c88
children 30739558a3e7
files extension/content/river.js extension/modules/RiverWriter.js extension/modules/datastore.js extension/modules/message.js
diffstat 4 files changed, 101 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/extension/content/river.js	Sun May 04 19:54:47 2008 -0700
+++ b/extension/content/river.js	Wed May 07 13:45:18 2008 -0700
@@ -41,18 +41,20 @@
 const Cr = Components.results;
 const Cu = Components.utils;
 
+Cu.import("resource://snowl/modules/collection.js");
 Cu.import("resource://snowl/modules/RiverWriter.js");
 
 var RiverHandler = {
-  /**
-   * The SnowlRiverWriter object that produces the UI.
-   */
-  _riverWriter: null,
+  // The set of messages to display in the view.
+  _collection: null,
   
+  // The object that generates the view.
+  _riverWriter: null,
+
   init: function SH_init() {
+    this._collection = new SnowlCollection();
     this._riverWriter = new SnowlRiverWriter();
-    this._riverWriter.init(window);
-    this._rebuildModel();
+    this._riverWriter.init(window, this._collection);
   },
 
   writeContent: function SH_writeContent() {
--- a/extension/modules/RiverWriter.js	Sun May 04 19:54:47 2008 -0700
+++ b/extension/modules/RiverWriter.js	Wed May 07 13:45:18 2008 -0700
@@ -219,7 +219,17 @@
 
   /**
    * Safely sets the href attribute on an anchor tag, providing the URI 
-   * specified can be loaded according to rules. 
+   * specified can be loaded according to rules.
+   *
+   * XXX Renamed from safeSetURIAttribute to unsafeSetURIAttribute to reflect
+   * that we've commented out the stuff that makes it safe.
+   *
+   * FIXME: I don't understand the security implications here, but presumably
+   * there's a reason this is here, and we should be respecting it, so make this
+   * work by giving each message in a collection have a reference to its source
+   * and then use the source's URI to create the principal with which we compare
+   * the URI.
+   * 
    * @param   element
    *          The element to set a URI attribute on
    * @param   attribute
@@ -227,8 +237,9 @@
    * @param   uri
    *          The URI spec to set as the href
    */
-  _safeSetURIAttribute: 
-  function FW__safeSetURIAttribute(element, attribute, uri) {
+  _unsafeSetURIAttribute: 
+  function FW__unsafeSetURIAttribute(element, attribute, uri) {
+/*
     var secman = Cc["@mozilla.org/scriptsecuritymanager;1"].
                  getService(Ci.nsIScriptSecurityManager);    
     const flags = Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL;
@@ -242,6 +253,7 @@
       // Not allowed to load this link because secman.checkLoadURIStr threw
       return;
     }
+*/
 
     this._contentSandbox.element = element;
     this._contentSandbox.uri = uri;
@@ -417,7 +429,7 @@
       
       // Set up the title image (supplied by the feed)
       var feedTitleImage = this._document.getElementById("feedTitleImage");
-      this._safeSetURIAttribute(feedTitleImage, "src", 
+      this._unsafeSetURIAttribute(feedTitleImage, "src", 
                                 parts.getPropertyAsAString("url"));
 
       // Set up the title image link
@@ -432,7 +444,7 @@
       this._contentSandbox.feedTitleLink = null;
       this._contentSandbox.titleText = null;
 
-      this._safeSetURIAttribute(feedTitleLink, "href", 
+      this._unsafeSetURIAttribute(feedTitleLink, "href", 
                                 parts.getPropertyAsAString("link"));
 
       // Fix the margin on the main title, so that the image doesn't run over
@@ -451,35 +463,34 @@
    * @param   container
    *          The container of entries in the feed
    */
-  _writeFeedContent: function FW__writeFeedContent(container) {
+  _writeFeedContent: function FW__writeFeedContent() {
     // Build the actual feed content
-    var feed = container.QueryInterface(Ci.nsIFeed);
-    if (feed.items.length == 0)
-      return;
+    //var feed = container.QueryInterface(Ci.nsIFeed);
+    //if (feed.items.length == 0)
+    //  return;
 
     this._contentSandbox.feedContent =
       this._document.getElementById("feedContent");
 
-    for (var i = 0; i < feed.items.length; ++i) {
-      var entry = feed.items.queryElementAt(i, Ci.nsIFeedEntry);
-      entry.QueryInterface(Ci.nsIFeedContainer);
+    for (let i = 0; i < this._collection.messages.length; ++i) {
+      let entry = this._collection.messages[i];
 
       var entryContainer = this._document.createElementNS(HTML_NS, "div");
       entryContainer.className = "entry";
 
       // If the entry has a title, make it a link
-      if (entry.title) {
+      if (entry.subject) {
         var a = this._document.createElementNS(HTML_NS, "a");
-        a.appendChild(this._document.createTextNode(entry.title.plainText()));
+        a.appendChild(this._document.createTextNode(entry.subject));
 
         // Entries are not required to have links, so entry.link can be null.
         if (entry.link)
-          this._safeSetURIAttribute(a, "href", entry.link.spec);
+          this._unsafeSetURIAttribute(a, "href", entry.link);
 
         var title = this._document.createElementNS(HTML_NS, "h3");
         title.appendChild(a);
 
-        var lastUpdated = this._parseDate(entry.updated);
+        var lastUpdated = this._parseDate(entry.timestamp);
         if (lastUpdated) {
           var dateDiv = this._document.createElementNS(HTML_NS, "div");
           dateDiv.className = "lastUpdated";
@@ -491,7 +502,13 @@
       }
 
       var body = this._document.createElementNS(HTML_NS, "div");
-      var summary = entry.summary || entry.content;
+
+      // The summary is currently not stored and made available, so we can
+      // only use the content.
+      // FIXME: use the summary instead once it becomes available.
+      //var summary = entry.summary || entry.content;
+      var summary = entry.content;
+
       var docFragment = null;
       if (summary) {
         if (summary.base)
@@ -504,10 +521,10 @@
 
         // If the entry doesn't have a title, append a # permalink
         // See http://scripting.com/rss.xml for an example
-        if (!entry.title && entry.link) {
+        if (!entry.subject && entry.link) {
           var a = this._document.createElementNS(HTML_NS, "a");
           a.appendChild(this._document.createTextNode("#"));
-          this._safeSetURIAttribute(a, "href", entry.link.spec);
+          this._unsafeSetURIAttribute(a, "href", entry.link);
           body.appendChild(this._document.createTextNode(" "));
           body.appendChild(a);
         }
@@ -617,7 +634,7 @@
 
       var enc_href = this._document.createElementNS(HTML_NS, "a");
       enc_href.appendChild(this._document.createTextNode(this._getURLDisplayName(enc.get("url"))));
-      this._safeSetURIAttribute(enc_href, "href", enc.get("url"));
+      this._unsafeSetURIAttribute(enc_href, "href", enc.get("url"));
       enclosureDiv.appendChild(enc_href);
 
       if (type_text && size_text)
@@ -889,8 +906,11 @@
   _document: null,
   _feedURI: null,
   _feedPrincipal: null,
+  _collection: null,
 
-  init: function FW_init(aWindow) {
+  init: function FW_init(aWindow, aCollection) {
+    this._collection = aCollection;
+
     // Explicitly wrap |window| in an XPCNativeWrapper to make sure
     // it's a real native object! This will throw an exception if we
     // get a non-native object.
@@ -920,13 +940,13 @@
 
     try {
       // Set up the feed content
-      var container = this._getContainer();
-      if (!container)
-        return;
+      //var container = this._getContainer();
+      //if (!container)
+      //  return;
 
-      this._setTitleText(container);
-      this._setTitleImage(container);
-      this._writeFeedContent(container);
+      //this._setTitleText(container);
+      //this._setTitleImage(container);
+      this._writeFeedContent();
     }
     finally {
       this._removeFeedFromCache();
--- a/extension/modules/datastore.js	Sun May 04 19:54:47 2008 -0700
+++ b/extension/modules/datastore.js	Wed May 07 13:45:18 2008 -0700
@@ -62,6 +62,7 @@
         ]
       },
 
+/*
       parts: {
         type: TABLE_TYPE_FULLTEXT,
         columns: [
@@ -70,6 +71,7 @@
           "content"
         ]
       },
+*/
 
       attributes: {
         type: TABLE_TYPE_NORMAL,
@@ -81,10 +83,11 @@
       },
 
       metadata: {
-        type: TABLE_TYPE_NORMAL,
+        type: TABLE_TYPE_FULLTEXT,
         columns: [
-          "messageID INTEGER REFERENCES messages(id)",
-          "attributeID INTEGER REFERENCES attributes(id)",
+          "messageID INTEGER NOT NULL REFERENCES messages(id)",
+          "attributeID INTEGER NOT NULL REFERENCES attributes(id)",
+          "contentType TEXT NOT NULL",
           "value BLOB"
         ]
       }
--- a/extension/modules/message.js	Sun May 04 19:54:47 2008 -0700
+++ b/extension/modules/message.js	Wed May 07 13:45:18 2008 -0700
@@ -5,6 +5,8 @@
 const Cr = Components.results;
 const Cu = Components.utils;
 
+Cu.import("resource://snowl/modules/datastore.js");
+
 function SnowlMessage(aID, aSubject, aAuthor, aLink, aTimestamp, aRead) {
   this.id = aID;
   this.subject = aSubject;
@@ -18,7 +20,44 @@
   id: null,
   subject: null,
   author: null,
+  // FIXME: make this an nsIURI.
   link: null,
   timestamp: null,
-  read: null
+  read: null,
+
+  // FIXME: also store and make available the summary.
+
+  get _contentStatement() {
+    let statement = SnowlDatastore.createStatement(
+      "SELECT content, contentType FROM parts WHERE messageID = :messageID"
+    );
+    this.__defineGetter__("_contentStatement", function() { return statement });
+    return this._contentStatement;
+  },
+
+  get content() {
+    let content;
+
+    try {
+      this._contentStatement.params.messageID = this.id;
+      if (this._contentStatement.step()) {
+        content = Cc["@mozilla.org/feed-textconstruct;1"].
+                  createInstance(Ci.nsIFeedTextConstruct);
+        content.text = this._contentStatement.row.content;
+        content.type = textConstructTypes[this._contentStatement.row.contentType];
+      }
+    }
+    finally {
+      this._contentStatement.reset();
+    }
+
+    return content;
+  }
+
 };
+
+let textConstructTypes = {
+  "text/html": "html",
+  "application/xhtml+xml": "xhtml",
+  "text/plain": "text"
+};