Mercurial > snowl
changeset 85:f5161c834622
store summaries in addition to content and display them in the river view
author | Myk Melez <myk@mozilla.org> |
---|---|
date | Fri, 16 May 2008 15:45:35 -0700 |
parents | 915e41848f6d |
children | 4d86f720af42 |
files | extension/content/river.js extension/modules/collection.js extension/modules/datastore.js extension/modules/feed.js extension/modules/message.js extension/modules/service.js |
diffstat | 6 files changed, 129 insertions(+), 95 deletions(-) [+] |
line wrap: on
line diff
--- a/extension/content/river.js Fri May 16 10:42:36 2008 -0700 +++ b/extension/content/river.js Fri May 16 15:45:35 2008 -0700 @@ -571,11 +571,7 @@ let body = this._document.createElementNS(HTML_NS, "div"); body.className = "body"; - // 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 = message.summary || message.content; - let summary = message.content; + let summary = message.content || message.summary; if (summary) { if (summary.base) body.setAttributeNS(XML_NS, "base", summary.base.spec);
--- a/extension/modules/collection.js Fri May 16 10:42:36 2008 -0700 +++ b/extension/modules/collection.js Fri May 16 15:45:35 2008 -0700 @@ -5,9 +5,23 @@ const Cr = Components.results; const Cu = Components.utils; +// FIXME: factor this out into a common file. +const PART_TYPE_CONTENT = 1; +const PART_TYPE_SUMMARY = 2; + +// Media type to nsIFeedTextConstruct::type mappings. +// FIXME: get this from message.js (or from something that both message.js +// and collection.js import). +const textConstructTypes = { + "text/html": "html", + "application/xhtml+xml": "xhtml", + "text/plain": "text" +}; + Cu.import("resource://snowl/modules/log4moz.js"); Cu.import("resource://snowl/modules/datastore.js"); Cu.import("resource://snowl/modules/message.js"); +Cu.import("resource://snowl/modules/URI.js"); /** * A group of messages. @@ -120,9 +134,9 @@ }, _getContent: function() { - let query = "SELECT messageID, content, contentType " + - "FROM parts " + - "WHERE parts.messageID IN (" + + let query = "SELECT messageID, content, mediaType, baseURI, languageCode " + + "FROM parts WHERE partType = " + PART_TYPE_CONTENT + + " AND messageID IN (" + this._messages.map(function(v) { return v.id }).join(",") + ")"; let statement = SnowlDatastore.createStatement(query); @@ -132,7 +146,9 @@ let content = Cc["@mozilla.org/feed-textconstruct;1"]. createInstance(Ci.nsIFeedTextConstruct); content.text = statement.row.content; - content.type = textConstructTypes[statement.row.contentType]; + content.type = textConstructTypes[statement.row.mediaType]; + content.base = URI.get(statement.row.baseURI); + content.lang = statement.row.languageCode; this._messageIndex[statement.row.messageID].content = content; } } @@ -222,11 +238,3 @@ return aObject; } - -// FIXME: get this from message.js (or from something that both message.js and collection.js import). -let textConstructTypes = { - "text/html": "html", - "application/xhtml+xml": "xhtml", - "text/plain": "text" -}; -
--- a/extension/modules/datastore.js Fri May 16 10:42:36 2008 -0700 +++ b/extension/modules/datastore.js Fri May 16 15:45:35 2008 -0700 @@ -71,8 +71,11 @@ type: TABLE_TYPE_FULLTEXT, columns: [ "messageID INTEGER NOT NULL REFERENCES messages(id)", - "contentType", - "content" + "partType INTEGER NOT NULL", + "content NOT NULL", + "mediaType TEXT", + "baseURI TEXT", + "languageCode TEXT", ] }, @@ -334,32 +337,6 @@ return this.dbConnection.lastInsertRowID; }, - get _insertPartStatement() { - let statement = this.createStatement( - "INSERT INTO parts(messageID, content, contentType) \ - VALUES (:messageID, :content, :contentType)" - ); - this.__defineGetter__("_insertPartStatement", function() { return statement }); - return this._insertPartStatement; - }, - - /** - * Insert a record into the parts table. - * - * @param aMessageID {integer} the record ID of the message - * @param aContentType {string} the Internet media type of the content - * @param aContent {string} the content - * - * @returns {integer} the ID of the newly-created record - */ - insertPart: function(aMessageID, aContent, aContentType) { - this._insertPartStatement.params.messageID = aMessageID; - this._insertPartStatement.params.content = aContent; - this._insertPartStatement.params.contentType = aContentType; - this._insertPartStatement.execute(); - return this.dbConnection.lastInsertRowID; - }, - get _selectAttributeIDStatement() { let statement = this.createStatement( "SELECT id FROM attributes WHERE name = :name"
--- a/extension/modules/feed.js Fri May 16 10:42:36 2008 -0700 +++ b/extension/modules/feed.js Fri May 16 15:45:35 2008 -0700 @@ -5,8 +5,13 @@ const Cr = Components.results; const Cu = Components.utils; +// FIXME: factor this out into a common file. +const PART_TYPE_CONTENT = 1; +const PART_TYPE_SUMMARY = 2; + Cu.import("resource://snowl/modules/log4moz.js"); Cu.import("resource://snowl/modules/datastore.js"); +Cu.import("resource://snowl/modules/URI.js"); var SnowlFeedClient = { // XXX Make this take a feed ID once it stores the list of subscribed feeds @@ -120,8 +125,8 @@ } }, - // nsIFeedTextConstruct::type to MIME media type mappings. - contentTypes: { html: "text/html", xhtml: "application/xhtml+xml", text: "text/plain" }, + // nsIFeedTextConstruct::type to media type mappings. + mediaTypes: { html: "text/html", xhtml: "application/xhtml+xml", text: "text/plain" }, getNewMessages: function() { let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(); @@ -180,14 +185,25 @@ // Convert the publication date/time string into a JavaScript Date object. let timestamp = aEntry.published ? new Date(aEntry.published) : null; - // Convert the content type specified by nsIFeedTextConstruct, which is - // either "html", "xhtml", or "text", into an Internet media type. - let contentType = aEntry.content ? this.contentTypes[aEntry.content.type] : null; - let contentText = aEntry.content ? aEntry.content.text : null; + // FIXME: wrap all queries that add the message into a transaction? + + // FIXME: handle titles that contain markup or are missing. let messageID = this.addSimpleMessage(this.id, aExternalID, aEntry.title.text, author, - timestamp, aEntry.link, - contentText, contentType); + timestamp, aEntry.link); + + // Add parts + if (aEntry.content) { + this.addPart(messageID, PART_TYPE_CONTENT, aEntry.content.text, + (aEntry.content.base ? aEntry.content.base.spec : null), + aEntry.content.lang, this.mediaTypes[aEntry.content.type]); + } + + if (aEntry.summary) { + this.addPart(messageID, PART_TYPE_SUMMARY, aEntry.summary.text, + (aEntry.summary.base ? aEntry.summary.base.spec : null), + aEntry.summary.lang, this.mediaTypes[aEntry.summary.type]); + } // Add metadata. let fields = aEntry.QueryInterface(Ci.nsIFeedContainer). @@ -302,18 +318,11 @@ * @param aTimestamp {Date} the date/time at which the message was sent * @param aLink {nsIURI} a link to the content of the message, * if the content is hosted on a server - * @param aContent {string} the content of the message, if the content - * is included with the message - * @param aContentType {string} the media type of the content of the message, - * if the content is included with the message * - * FIXME: allow callers to pass a set of arbitrary metadata name/value pairs - * that get written to the attributes table. - * * @returns {integer} the internal ID of the newly-created message */ addSimpleMessage: function(aSourceID, aExternalID, aSubject, aAuthor, - aTimestamp, aLink, aContent, aContentType) { + aTimestamp, aLink) { // Convert the timestamp to milliseconds-since-epoch, which is how we store // it in the datastore. let timestamp = aTimestamp ? aTimestamp.getTime() : null; @@ -326,10 +335,29 @@ SnowlDatastore.insertMessage(aSourceID, aExternalID, aSubject, aAuthor, timestamp, link); - if (aContent) - SnowlDatastore.insertPart(messageID, aContent, aContentType); + return messageID; + }, + + get _addPartStatement() { + let statement = SnowlDatastore.createStatement( + "INSERT INTO parts(messageID, partType, content, baseURI, languageCode, mediaType) \ + VALUES (:messageID, :partType, :content, :baseURI, :languageCode, :mediaType)" + ); + this.__defineGetter__("_addPartStatement", function() { return statement }); + return this._addPartStatement; + }, - return messageID; + addPart: function(aMessageID, aPartType, aContent, aBaseURI, aLanguageCode, + aMediaType) { + this._addPartStatement.params.messageID = aMessageID; + this._addPartStatement.params.partType = aPartType; + this._addPartStatement.params.content = aContent; + this._addPartStatement.params.baseURI = aBaseURI; + this._addPartStatement.params.languageCode = aLanguageCode; + this._addPartStatement.params.mediaType = aMediaType; + this._addPartStatement.execute(); + + return SnowlDatastore.dbConnection.lastInsertRowID; }, addMetadatum: function(aMessageID, aAttributeName, aValue) {
--- a/extension/modules/message.js Fri May 16 10:42:36 2008 -0700 +++ b/extension/modules/message.js Fri May 16 15:45:35 2008 -0700 @@ -5,8 +5,22 @@ const Cr = Components.results; const Cu = Components.utils; +// FIXME: factor this out into a common file. +const PART_TYPE_CONTENT = 1; +const PART_TYPE_SUMMARY = 2; + +// Media type to nsIFeedTextConstruct::type mappings. +// FIXME: get this from message.js (or from something that both message.js +// and collection.js import). +const textConstructTypes = { + "text/html": "html", + "application/xhtml+xml": "xhtml", + "text/plain": "text" +}; + Cu.import("resource://snowl/modules/datastore.js"); Cu.import("resource://snowl/modules/source.js"); +Cu.import("resource://snowl/modules/URI.js"); function SnowlMessage(aID, aSubject, aAuthor, aLink, aTimestamp, aRead) { this.id = aID; @@ -41,41 +55,57 @@ " WHERE id = " + this.id); }, - - // FIXME: also store and make available the summary. + _content: null, + get content() { + if (!this._content) + this._content = this._getPart(PART_TYPE_CONTENT); + return this._content; + }, + set content(newValue) { + this._content = newValue; + }, - get _contentStatement() { - let statement = SnowlDatastore.createStatement( - "SELECT content, contentType FROM parts WHERE messageID = :messageID" - ); - this.__defineGetter__("_contentStatement", function() { return statement }); - return this._contentStatement; + _summary: null, + get summary() { + if (!this._summary) + this._summary = this._getPart(PART_TYPE_SUMMARY); + return this._summary; + }, + set summary(newValue) { + this._summary = newValue; }, - _content: null, + get _getPartStatement() { + let statement = SnowlDatastore.createStatement( + "SELECT content, mediaType, baseURI, languageCode FROM parts " + + "WHERE messageID = :messageID AND partType = :partType" + ); + this.__defineGetter__("_getPartStatement", function() { return statement }); + return this._getPartStatement; + }, - get content() { - if (this._content) - return this._content; + _getPart: function(aPartType) { + let part; try { - this._contentStatement.params.messageID = this.id; - if (this._contentStatement.step()) { - this._content = Cc["@mozilla.org/feed-textconstruct;1"]. - createInstance(Ci.nsIFeedTextConstruct); - this._content.text = this._contentStatement.row.content; - this._content.type = textConstructTypes[this._contentStatement.row.contentType]; + this._getPartStatement.params.messageID = this.id; + this._getPartStatement.params.partType = aPartType; + if (this._getPartStatement.step()) { + // FIXME: instead of a text construct, return a JS object that knows + // its ID and part type. + part = Cc["@mozilla.org/feed-textconstruct;1"]. + createInstance(Ci.nsIFeedTextConstruct); + part.text = this._getPartStatement.row.content; + part.type = textConstructTypes[this._getPartStatement.row.mediaType]; + part.base = URI.get(this._getPartStatement.row.baseURI); + part.lang = this._getPartStatement.row.languageCode; } } finally { - this._contentStatement.reset(); + this._getPartStatement.reset(); } - return this._content; - }, - - set content(newValue) { - this._content = newValue; + return part; }, // FIXME: for performance, make this a class property rather than an instance @@ -104,9 +134,3 @@ } }; - -let textConstructTypes = { - "text/html": "html", - "application/xhtml+xml": "xhtml", - "text/plain": "text" -};
--- a/extension/modules/service.js Fri May 16 10:42:36 2008 -0700 +++ b/extension/modules/service.js Fri May 16 15:45:35 2008 -0700 @@ -9,6 +9,7 @@ Cu.import("resource://snowl/modules/log4moz.js"); Cu.import("resource://snowl/modules/datastore.js"); Cu.import("resource://snowl/modules/feed.js"); +Cu.import("resource://snowl/modules/source.js"); Cu.import("resource://snowl/modules/URI.js"); const PERMS_FILE = 0644; @@ -171,7 +172,7 @@ }, get _getSourcesStatement() { - let statement = this.createStatement( + let statement = SnowlDatastore.createStatement( "SELECT id, name, machineURI, humanURI, lastRefreshed, importance FROM sources" ); delete this._getSourcesStatement;