diff --git a/lib/rss.js b/lib/rss.js index 11ca4915..8199b629 100755 --- a/lib/rss.js +++ b/lib/rss.js @@ -10,6 +10,16 @@ function ifTruePush(bool, array, data) { } } +function ifTruePushArray(bool, array, dataArray) { + if(!bool) { + return; + } + + dataArray.forEach(function(item) { + ifTruePush(item, array, item); + }); +} + function generateXML (data){ var channel = []; @@ -40,6 +50,8 @@ function generateXML (data){ }); } + ifTruePushArray(data.custom_elements, channel, data.custom_elements); + data.items.forEach(function(item) { var item_values = [ { title: { _cdata: item.title } } @@ -84,6 +96,8 @@ function generateXML (data){ } } + ifTruePushArray(item.custom_elements, item_values, item.custom_elements); + channel.push({ item: item_values }); }); @@ -96,6 +110,10 @@ function generateXML (data){ version: '2.0' }; + Object.keys(data.custom_namespaces).forEach(function(name) { + _attr['xmlns:' + name] = data.custom_namespaces[name]; + }); + //only add namespace if GeoRSS is true if(data.geoRSS){ _attr['xmlns:geo'] = 'http://www.w3.org/2003/01/geo/wgs84_pos#'; @@ -112,39 +130,42 @@ function generateXML (data){ function RSS (options, items) { options = options || {}; - this.title = options.title || 'Untitled RSS Feed'; - this.description = options.description || ''; - this.generator = options.generator || 'RSS for Node'; - this.feed_url = options.feed_url; - this.site_url = options.site_url; - this.image_url = options.image_url; - this.author = options.author; - this.categories = options.categories; - this.pubDate = options.pubDate; - this.hub = options.hub; - this.docs = options.docs; - this.copyright = options.copyright; - this.language = options.language; - this.managingEditor = options.managingEditor; - this.webMaster = options.webMaster; - this.ttl = options.ttl; + this.title = options.title || 'Untitled RSS Feed'; + this.description = options.description || ''; + this.generator = options.generator || 'RSS for Node'; + this.feed_url = options.feed_url; + this.site_url = options.site_url; + this.image_url = options.image_url; + this.author = options.author; + this.categories = options.categories; + this.pubDate = options.pubDate; + this.hub = options.hub; + this.docs = options.docs; + this.copyright = options.copyright; + this.language = options.language; + this.managingEditor = options.managingEditor; + this.webMaster = options.webMaster; + this.ttl = options.ttl; //option to return feed as GeoRSS is set automatically if feed.lat/long is used - this.geoRSS = options.geoRSS || false; - this.items = items || []; + this.geoRSS = options.geoRSS || false; + this.custom_namespaces = options.custom_namespaces || {}; + this.custom_elements = options.custom_elements || []; + this.items = items || []; this.item = function (options) { options = options || {}; var item = { - title: options.title || 'No title', - description: options.description || '', - url: options.url, - guid: options.guid, - categories: options.categories || [], - author: options.author, - date: options.date, - lat: options.lat, - long: options.long, - enclosure: options.enclosure || false + title: options.title || 'No title', + description: options.description || '', + url: options.url, + guid: options.guid, + categories: options.categories || [], + author: options.author, + date: options.date, + lat: options.lat, + long: options.long, + enclosure: options.enclosure || false, + custom_elements: options.custom_elements || [] }; this.items.push(item); diff --git a/readme.md b/readme.md index 95d5e27c..dec89201 100644 --- a/readme.md +++ b/readme.md @@ -37,6 +37,8 @@ var feed = new RSS(feedOptions); * `pubDate` _optional_ **Date object or date string** The publication date for content in the feed * `ttl` _optional_ **integer** Number of minutes feed can be cached before refreshing from source. * `hub` _optional_ **PubSubHubbub hub url** Where is the PubSubHub hub located. + * `custom_namespaces` _optional_ **object** Put additional namespaces in element (without 'xmlns:' prefix) + * `custom_elements` _optional_ **array** Put additional elements in the feed (node-xml syntax) #### Add items to a feed @@ -64,6 +66,7 @@ feed.item(itemOptions); if the content should be presented as unread. * `lat` _optional_ **number** The latitude coordinate of the item. * `long` _optional_ **number** The longitude coordinate of the item. + * `custom_elements` _optional_ **array** Put additional elements in the item (node-xml syntax) ##### Feed XML @@ -96,7 +99,34 @@ var feed = new RSS({ language: 'en', categories: ['Category 1','Category 2','Category 3'], pubDate: 'May 20, 2012 04:00:00 GMT', - ttl: '60' + ttl: '60', + customNamespaces: { + 'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd' + }, + custom: [ + {'itunes:subtitle': 'A show about everything'}, + {'itunes:author': 'John Doe'}, + {'itunes:summary': 'All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store'}, + {'itunes:owner': [ + {'itunes:name': 'John Doe'}, + {'itunes:email': 'john.doe@example.com'} + ]}, + {'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything.jpg' + } + }}, + {'itunes:category': [ + {_attr: { + text: 'Technology' + }}, + {'itunes:category': { + _attr: { + text: 'Gadgets' + } + }} + ]} + ] }); /* loop over data and add to feed */ @@ -110,7 +140,17 @@ feed.item({ date: 'May 27, 2012', // any format that js Date can parse. lat: 33.417974, //optional latitude field for GeoRSS long: -111.933231, //optional longitude field for GeoRSS - enclosure: {url:'...', file:'path-to-file'} // optional enclosure + enclosure: {url:'...', file:'path-to-file'}, // optional enclosure + custom: [ + {'itunes:author': 'John Doe'}, + {'itunes:subtitle': 'A short primer on table spices'}, + {'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything/Episode1.jpg' + } + }}, + {'itunes:duration': '7:04'} + ] }); // cache the xml to send to clients diff --git a/test/rss.test.js b/test/rss.test.js index d035797a..39df2d6c 100644 --- a/test/rss.test.js +++ b/test/rss.test.js @@ -262,5 +262,201 @@ describe('rss module', function(done) { expect(result).to.equal(expectedResult); done(); }); -}); + it('should work with custom elements', function(done) { + var feed = new RSS({ + title: 'title', + description: 'description', + feed_url: 'http://example.com/rss.xml', + site_url: 'http://example.com', + author: 'Dylan Greene', + pubDate: 'May 20, 2012 04:00:00 GMT', + language: 'en', + ttl: '60', + custom_elements: [ + {'itunes:subtitle': 'A show about everything'}, + {'itunes:author': 'John Doe'}, + {'itunes:summary': 'All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store'}, + {'itunes:owner': [ + {'itunes:name': 'John Doe'}, + {'itunes:email': 'john.doe@example.com'} + ]}, + {'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything.jpg' + } + }}, + {'itunes:category': [ + {_attr: { + text: 'Technology' + }}, + {'itunes:category': { + _attr: { + text: 'Gadgets' + } + }} + ]} + ] + }); + + feed.item({ + title: 'item 1', + description: 'description 1', + url: 'http://example.com/article1', + date: 'May 24, 2012 04:00:00 GMT', + custom_elements: [ + {'itunes:author': 'John Doe'}, + {'itunes:subtitle': 'A short primer on table spices'}, + {'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything/Episode1.jpg' + } + }}, + {'itunes:duration': '7:04'} + ] + }); + + var expectedResult ='\n'+ + ''+ + '' + + '<![CDATA[title]]>' + + '' + + 'http://example.com' + + 'RSS for Node' + + '' + new Date().toUTCString() +'' + + '' + + '' + + 'Sun, 20 May 2012 04:00:00 GMT' + + '' + + '60' + + 'A show about everything' + + 'John Doe' + + 'All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store' + + '' + + 'John Doe' + + 'john.doe@example.com' + + '' + + '' + + '' + + '' + + '' + + '' + + '<![CDATA[item 1]]>' + + '' + + 'http://example.com/article1' + + 'http://example.com/article1' + + '' + + 'Thu, 24 May 2012 04:00:00 GMT' + + 'John Doe' + + 'A short primer on table spices' + + '' + + '7:04' + + '' + + '' + + ''; + var result = feed.xml(); + + expect(result).to.equal(expectedResult); + done(); + }); + + it('should work with custom namespaces', function(done) { + var feed = new RSS({ + title: 'title', + description: 'description', + feed_url: 'http://example.com/rss.xml', + site_url: 'http://example.com', + author: 'Dylan Greene', + pubDate: 'May 20, 2012 04:00:00 GMT', + language: 'en', + ttl: '60', + custom_namespaces: { + 'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd' + }, + custom_elements: [ + {'itunes:subtitle': 'A show about everything'}, + {'itunes:author': 'John Doe'}, + {'itunes:summary': 'All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store'}, + {'itunes:owner': [ + {'itunes:name': 'John Doe'}, + {'itunes:email': 'john.doe@example.com'} + ]}, + {'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything.jpg' + } + }}, + {'itunes:category': [ + {_attr: { + text: 'Technology' + }}, + {'itunes:category': { + _attr: { + text: 'Gadgets' + } + }} + ]} + ] + }); + + feed.item({ + title: 'item 1', + description: 'description 1', + url: 'http://example.com/article1', + date: 'May 24, 2012 04:00:00 GMT', + custom_elements: [ + {'itunes:author': 'John Doe'}, + {'itunes:subtitle': 'A short primer on table spices'}, + {'itunes:image': { + _attr: { + href: 'http://example.com/podcasts/everything/AllAboutEverything/Episode1.jpg' + } + }}, + {'itunes:duration': '7:04'} + ] + }); + + var expectedResult ='\n'+ + ''+ + '' + + '<![CDATA[title]]>' + + '' + + 'http://example.com' + + 'RSS for Node' + + '' + new Date().toUTCString() +'' + + '' + + '' + + 'Sun, 20 May 2012 04:00:00 GMT' + + '' + + '60' + + 'A show about everything' + + 'John Doe' + + 'All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store' + + '' + + 'John Doe' + + 'john.doe@example.com' + + '' + + '' + + '' + + '' + + '' + + '' + + '<![CDATA[item 1]]>' + + '' + + 'http://example.com/article1' + + 'http://example.com/article1' + + '' + + 'Thu, 24 May 2012 04:00:00 GMT' + + 'John Doe' + + 'A short primer on table spices' + + '' + + '7:04' + + '' + + '' + + ''; + var result = feed.xml(); + + expect(result).to.equal(expectedResult); + done(); + }); +});