1 ///////////////////////////////////////////////////////////////////////////////
\r
2 // The FeedUpdateBroker class implements a simple RSS fetcher and parser.
\r
5 function FeedUpdateBroker() {
\r
7 this.callback = null;
\r
10 // Fetches a feed from the specified URL and calls the callback when the feed
\r
11 // has been fetched and parsed, or if the process results in an error.
\r
12 FeedUpdateBroker.prototype.fetchFeed = function(feedURL, callback) {
\r
13 // remember callback
\r
14 this.callback = callback;
\r
16 // create new XML HTTP request
18 //netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
\r
19 this.httpReq = new Ajax();
\r
23 this.httpReq.onreadystatechange = function() { self.readyStateChanged(); };
\r
25 // append the current time after the URL to bypass caches
\r
26 var fullURL = feedURL;
\r
27 if (fullURL.indexOf("?") == -1) {
\r
32 fullURL += "nocache=" + (new Date().getTime());
\r
34 // initiate the request
\r
35 this.httpReq.open("GET", fullURL, true);
\r
36 this.httpReq.send(null);
\r
39 // Callback for ready-state change events in the XML HTTP request.
\r
40 FeedUpdateBroker.prototype.readyStateChanged = function() {
\r
41 // complete request?
\r
42 if (this.httpReq.readyState == 4) {
\r
43 // attempt to get response status
\r
44 var responseStatus = null;
\r
46 responseStatus = this.httpReq.status;
\r
47 } catch (noStatusException) {}
\r
49 // handle the response and call the registered callback
\r
50 this.callback.call(this, this.handleResponse(responseStatus, this.httpReq.responseXML));
\r
54 // Handles a completed response.
\r
55 FeedUpdateBroker.prototype.handleResponse = function(responseStatus, xmlDoc) {
\r
56 if (((responseStatus == 200)||(responseStatus == 0)) && xmlDoc != null) {
\r
57 // node ref for iterating
\r
60 // get last modified time - default to current time
\r
61 var lastModified = new Date().getTime();
\r
62 var channelElements = xmlDoc.getElementsByTagName("channel");
\r
63 if (channelElements.length > 0) {
\r
64 node = channelElements[0].firstChild;
\r
65 while (node != null) {
\r
66 if (node.nodeType == Node.ELEMENT_NODE) {
\r
67 if (node.nodeName == "pubDate" ||
\r
68 node.nodeName == "lastBuildDate" ||
\r
69 node.nodeName == "dc:date") {
\r
70 lastModified = this.getTextOfNode(node);
\r
74 node = node.nextSibling;
\r
78 // init feed items array
\r
81 // we got the feed XML so now we'll parse it
\r
82 var itemElements = xmlDoc.getElementsByTagName("item");
\r
83 for (var i = 0; i < itemElements.length; i++) {
\r
84 // iterate through child nodes of this item and gather
\r
85 // all the data we need for a feed item
\r
88 var description = null;
\r
91 node = itemElements[i].firstChild;
\r
92 while (node != null) {
\r
93 if (node.nodeType == Node.ELEMENT_NODE) {
\r
94 if (node.nodeName == "title") {
\r
96 title = this.getTextOfNode(node);
\r
97 } else if (node.nodeName == "pubDate" || node.nodeName == "dc:date") {
\r
98 // item publishing date
\r
99 date = this.getTextOfNode(node);
\r
100 } else if (node.nodeName == "description") {
\r
101 // item description
\r
102 description = this.getTextOfNode(node);
\r
103 } else if (node.nodeName == "link") {
\r
105 url = this.getTextOfNode(node);
\r
108 node = node.nextSibling;
\r
111 // create the item and add to the items array
\r
112 items.push({ title: title, date: date, description: description, url: url });
\r
115 // update was completed successfully
\r
116 return { status: "ok", lastModified: lastModified, items: items };
\r
119 return { status: "error" };
\r
123 // Returns the text of a node.
\r
124 FeedUpdateBroker.prototype.getTextOfNode = function(node) {
\r
127 // iterate through all child elements and collect all text to the buffer
\r
128 var child = node.firstChild;
\r
129 while (child != null) {
\r
130 if (child.nodeType == Node.TEXT_NODE || child.nodeType == Node.CDATA_SECTION_NODE) {
\r
131 // append text to buffer
\r
135 buf += child.nodeValue;
\r
137 child = child.nextSibling;
\r
140 // strip all tags from the buffer
\r
141 var strippedBuf = "";
\r
142 var textStartPos = -1;
\r
143 var tagBalance = 0;
\r
145 // iterate through the text and append all text to the stripped buffer
\r
146 // that is at a tag balance of 0
\r
147 for (pos = 0; pos < buf.length; pos++) {
\r
148 var c = buf.charAt(pos);
\r
151 if (tagBalance == 0 && textStartPos != -1) {
\r
152 // everything up to here was valid text
\r
153 strippedBuf += buf.substring(textStartPos, pos);
\r
157 } else if (c == '>') {
\r
161 } else if (tagBalance == 0 && textStartPos == -1) {
\r
162 // first char of text
\r
163 textStartPos = pos;
\r
167 // add remaining text - if any
\r
168 if (tagBalance == 0 && textStartPos != -1) {
\r
169 strippedBuf += buf.substring(textStartPos, pos);
\r
172 return strippedBuf;
\r