Symbian.org/FeedUpdateBroker.js
changeset 0 54498df70f5d
child 3 9cbe91927e89
equal deleted inserted replaced
-1:000000000000 0:54498df70f5d
       
     1 ///////////////////////////////////////////////////////////////////////////////
       
     2 // The FeedUpdateBroker class implements a simple RSS fetcher and parser.
       
     3 // Adapted from WRTKit RssReader example
       
     4 
       
     5 // Constructor.
       
     6 function FeedUpdateBroker() {
       
     7     this.httpReq = null;
       
     8     this.feedAddress = null;
       
     9     this.callback = null;
       
    10 	this.ignoreContent = false;
       
    11 	this.cancelled = false;
       
    12 	this.responseParser = this.handleRssResponse;
       
    13 	this.startFromItem = 0;
       
    14 	this.maxItems = 0;
       
    15 }
       
    16 
       
    17 // Fetches a feed from the specified URL and calls the callback when the feed
       
    18 // has been fetched and parsed, or if the process results in an error.
       
    19 FeedUpdateBroker.prototype.doFetchFeed = function(){    
       
    20     // create new XML HTTP request
       
    21     this.httpReq = new Ajax();
       
    22     
       
    23     // set callback
       
    24     var self = this;
       
    25     this.httpReq.onreadystatechange = function() { self.readyStateChanged(); };
       
    26 
       
    27 	var fullURL = this.feedAddress;
       
    28     if (fullURL.indexOf("?") == -1) {
       
    29         fullURL += "?";
       
    30     } else {
       
    31         fullURL += "&";
       
    32     }
       
    33     fullURL += "nocache=" + (new Date().getTime());
       
    34 
       
    35     // initiate the request
       
    36     this.httpReq.open("GET", fullURL, true);
       
    37     this.httpReq.send(null);
       
    38 }
       
    39 
       
    40 // has been fetched and parsed, or if the process results in an error.
       
    41 FeedUpdateBroker.prototype.fetchFeed = function(feedURL, callback) {
       
    42     // remember callback
       
    43     this.callback = callback;
       
    44     this.feedAddress = feedURL;
       
    45 	this.doFetchFeed();
       
    46 }
       
    47 
       
    48 // Callback for ready-state change events in the XML HTTP request.
       
    49 FeedUpdateBroker.prototype.readyStateChanged = function() {
       
    50     // complete request?
       
    51     if (this.httpReq.readyState == 4) {
       
    52         // attempt to get response status
       
    53         var responseStatus = null;
       
    54         try {
       
    55             responseStatus = this.httpReq.status;
       
    56         } catch (noStatusException) {}
       
    57         
       
    58 		// are we being prompted for login?
       
    59 		var text = this.httpReq.responseText;
       
    60 		if ( isLoginPrompt (text) ) {
       
    61 			var self = this;
       
    62 			login(function(){self.doFetchFeed();});
       
    63 			return;
       
    64 		}
       
    65 		
       
    66         // handle the response and call the registered callback object
       
    67 		var response = this.httpReq.responseXML;
       
    68 		if (response == null) {
       
    69 			// if the content type is not set correctly, we get the response as text
       
    70 			var xmlparser = new DOMParser();
       
    71 		    response = xmlparser.parseFromString(this.httpReq.responseText, "text/xml");
       
    72 		}
       
    73         this.callback.feedUpdateCompleted(this.handleResponse(responseStatus, response));
       
    74     }
       
    75 }
       
    76 
       
    77 // Handles a completed response.
       
    78 FeedUpdateBroker.prototype.handleResponse = function(responseStatus, xmlDoc){
       
    79 	if (this.responseParser == null) {
       
    80 		return this.handleRssResponse(responseStatus, xmlDoc);
       
    81 	}
       
    82 	else {
       
    83 		return this.responseParser.call(this, this, responseStatus, xmlDoc);
       
    84 	}	
       
    85 }
       
    86 
       
    87 
       
    88 FeedUpdateBroker.prototype.handleRssResponse = function(broker, responseStatus, xmlDoc){
       
    89 	if ( this.cancelled ) {
       
    90         return { status: "cancelled" };
       
    91 	}
       
    92     if (responseStatus == 200 && xmlDoc != null) {
       
    93         // node ref for iterating
       
    94         var node;
       
    95         
       
    96         // get last modified time - default to current time
       
    97         var lastModified = new Date().getTime();
       
    98         var channelElements = xmlDoc.getElementsByTagName("channel");
       
    99         if (channelElements.length > 0) {
       
   100             node = channelElements[0].firstChild;
       
   101             while (node != null) {
       
   102                 if (node.nodeType == Node.ELEMENT_NODE) {
       
   103                     if (node.nodeName == "pubDate" ||
       
   104                             node.nodeName == "lastBuildDate" ||
       
   105                             node.nodeName == "dc:date") {
       
   106                         lastModified = getTextOfNode(node);
       
   107                         break;
       
   108                     }
       
   109                 }
       
   110                 node = node.nextSibling;
       
   111             }
       
   112         }
       
   113         
       
   114         // init feed items array
       
   115         var items = [];
       
   116         
       
   117         // we got the feed XML so now we'll parse it
       
   118         var itemElements = xmlDoc.getElementsByTagName("item");
       
   119 		
       
   120         for (var i = this.startFromItem; i < itemElements.length; i++) {
       
   121 			if ( this.maxItems > 0 && this.maxItems < i ) {
       
   122 				break;
       
   123 			}
       
   124             // iterate through child nodes of this item and gather
       
   125             // all the data we need for a feed item
       
   126             var title = null;
       
   127             var date = null;
       
   128             var description = null;
       
   129             var url = null;
       
   130             var author = null;
       
   131             node = itemElements[i].firstChild;
       
   132             while (node != null) {
       
   133                 if (node.nodeType == Node.ELEMENT_NODE) {
       
   134                     if (node.nodeName == "title") {
       
   135                         // item title
       
   136                         title = getTextOfNode(node);
       
   137                     } else if (node.nodeName == "pubDate" || node.nodeName == "dc:date") {
       
   138                         // item publishing date
       
   139                         date = getTextOfNode(node);
       
   140                     } else if (node.nodeName == "description" && !this.ignoreContent ) {
       
   141                         // item description
       
   142                         description = getTextOfNode(node);
       
   143                     } else if (node.nodeName == "link") {
       
   144                         // link URL
       
   145                         url = getTextOfNode(node);
       
   146                     } else if (node.nodeName == "dc:creator" ) {
       
   147 						author = getTextOfNode(node);
       
   148 					}
       
   149                 }
       
   150                 node = node.nextSibling;
       
   151             }
       
   152             
       
   153             // create the item and add to the items array
       
   154             items.push({ title: title, date: date, description: description, url: url, author: author });
       
   155         }
       
   156         
       
   157         // update was completed successfully
       
   158         return { status: "ok", lastModified: lastModified, items: items };
       
   159     } else {
       
   160         // update failed
       
   161         return { status: "error" };
       
   162     }
       
   163 }
       
   164 
       
   165 // Returns the text of a node.
       
   166 function getTextOfNode(node) {
       
   167     var buf = "";
       
   168     
       
   169     // iterate through all child elements and collect all text to the buffer
       
   170     var child = node.firstChild;
       
   171     while (child != null) {
       
   172         if (child.nodeType == Node.TEXT_NODE || child.nodeType == Node.CDATA_SECTION_NODE) {
       
   173             // append text to buffer
       
   174             if (buf != "") {
       
   175                 buf += " ";
       
   176             }
       
   177             buf += child.nodeValue;
       
   178         }
       
   179         child = child.nextSibling;
       
   180     }
       
   181     
       
   182     // strip all tags from the buffer
       
   183     var strippedBuf = "";
       
   184     var textStartPos = -1;
       
   185     var tagBalance = 0;
       
   186     
       
   187     // iterate through the text and append all text to the stripped buffer
       
   188     // that is at a tag balance of 0
       
   189     for (pos = 0; pos < buf.length; pos++) {
       
   190         var c = buf.charAt(pos);
       
   191         if (c == '<') {
       
   192             // entering a tag
       
   193             if (tagBalance == 0 && textStartPos != -1) {
       
   194                 // everything up to here was valid text
       
   195                 strippedBuf += buf.substring(textStartPos, pos);
       
   196                 textStartPos = -1;
       
   197             }
       
   198             tagBalance++;
       
   199         } else if (c == '>') {
       
   200             // leaving a tag
       
   201             tagBalance--;
       
   202             textStartPos = -1;
       
   203         } else if (tagBalance == 0 && textStartPos == -1) {
       
   204             // first char of text
       
   205             textStartPos = pos;
       
   206         }
       
   207     }
       
   208     
       
   209     // add remaining text - if any
       
   210     if (tagBalance == 0 && textStartPos != -1) {
       
   211         strippedBuf += buf.substring(textStartPos, pos);
       
   212     }
       
   213     
       
   214     return strippedBuf;
       
   215 }
       
   216 
       
   217 FeedUpdateBroker.prototype.cancel = function() {
       
   218 	this.cancelled = true;
       
   219 	this.httpReq.abort();
       
   220 }