3 * https://camagu.github.com/jquery-feeds
5 * Copyright (c) 2013, Camilo Aguilar
6 * Dual licensed under the MIT and GPL licenses:
7 * http://www.opensource.org/licenses/mit-license.php
8 * http://www.gnu.org/licenses/gpl.html
10 * Includes a modified version of Simple JavaScript Templating
11 * http://ejohn.org/blog/javascript-micro-templating/
12 * Copyright (c) John Resig (http://ejohn.org)
18 /*jshint evil: true */
23 $.fn
.feeds = function( options
) {
26 service
: '//ajax.googleapis.com/ajax/services/feed/load?v=1.0',
29 loadingTemplate
: '<div class="feeds-loader">Loading entries ...</div>',
30 entryTemplate
: '<div class="feeds-entry feeds-source-<!=source!>">' +
31 '<a class="feeds-entry-title" target="_blank" href="<!=link!>" title="<!=title!>"><!=title!></a>' +
32 '<div class="feeds-entry-date"><!=publishedDate!></div>' +
33 '<div class="feeds-entry-contentSnippet"><!=contentSnippet!></div>' +
39 onComplete: function( entries
) {
42 preprocess: function( feed
) {
56 init: function( element
, options
) {
57 this.settings
= $.extend( this.settings
, options
);
58 this.feeds
= this.settings
.feeds
;
60 for ( var i
in this.feeds
) {
61 if ( this.feeds
.hasOwnProperty( i
) ) {
66 var protocol
= this.settings
.ssl
=== 'auto' ? document
.location
.protocol
: this.settings
.ssl
? 'https:' : 'http:';
67 if ( $.inArray( protocol
, [ 'http:', 'https' ]) === -1 ) {
71 this.service
= protocol
+ this.service
;
73 this.$element
= $( element
);
75 var render
= typeof this.settings
.loadingTemplate
=== 'function' ? this.settings
.loadingTemplate
: this.tmpl( this.settings
.loadingTemplate
);
76 this.$loader
= $( render
.call( this, { } ) );
77 this.$element
.html( this.$loader
);
79 var output
= this.settings
.xml
? 'json_xml' : 'json';
81 for ( var j
in this.feeds
) {
82 this.fetchFeed( j
, this.feeds
[ j
], this.settings
.max
, output
);
86 fetchFeed: function( key
, feed
, max
, output
) {
89 var cacheKey
= feed
+ '**' + max
+ '**' + output
;
90 if ( typeof cache
[ cacheKey
] !== 'undefined' ) {
91 self
.processResponse( cache
[ cacheKey
], key
, feed
);
103 beforeSend: function( ) {
107 success: function( data
) {
108 cache
[ cacheKey
] = data
;
109 self
.processResponse( data
, this.key
, this.feed
);
114 processResponse: function( data
, key
, feed
) {
115 if ( data
.responseStatus
!== 200 ) {
116 if ( window
.console
&& window
.console
.log
) {
117 console
.log( 'Unable to load feed ' + feed
+ ': (' + data
.responseStatus
+ ') ' + data
.responseDetails
);
120 var currentFeed
= data
.responseData
.feed
;
121 var feedEntries
= currentFeed
.entries
;
123 var type
= data
.responseData
.feed
.type
;
125 if ( this.settings
.xml
) {
126 var $xml
= $( data
.responseData
.xmlString
);
128 if ( type
.match( /^rss.*/ ) ) {
129 $xml
= $xml
.filter( 'rss' ).find( 'channel' );
130 } else if ( type
.match( /^atom.*/ ) ) {
131 $xml
= $xml
.filter( 'feed' );
134 currentFeed
.xml
= $xml
;
137 for ( var i
in feedEntries
) {
138 var entry
= $.extend( {}, feedEntries
[ i
] );
140 entry
.publishedDateRaw
= entry
.publishedDate
;
142 entry
.feedUrl
= currentFeed
.feedUrl
;
143 entry
.feedTitle
= currentFeed
.title
;
144 entry
.feedLink
= currentFeed
.link
;
145 entry
.feedDescription
= currentFeed
.description
;
146 entry
.feedAuthor
= currentFeed
.author
;
148 if ( this.settings
.xml
) {
149 if ( type
.match( /^rss.*/ ) ) {
150 entry
.xml
= currentFeed
.xml
.find( 'item' ).eq( i
);
151 } else if ( type
.match( /^atom.*/ ) ) {
152 entry
.xml
= currentFeed
.xml
.find( 'entry' ).eq( i
);
158 if ( this.settings
.preprocess
.call( entry
, currentFeed
) !== false ) {
159 this.entries
.push( entry
);
165 this.checkComplete();
168 checkComplete: function( ) {
169 if ( this.feedsLoaded
=== this.feedsLength
) {
170 this.$loader
.remove( );
172 this.entries
.sort( function( a
, b
) {
173 var aDate
= new Date( a
.publishedDateRaw
).getTime( );
174 var bDate
= new Date( b
.publishedDateRaw
).getTime( );
176 return bDate
- aDate
;
179 var render
= typeof this.settings
.entryTemplate
=== 'function' ? this.settings
.entryTemplate
: this.tmpl( this.settings
.entryTemplate
);
181 for ( var i
in this.entries
) {
182 var entry
= this.entries
[ i
];
184 var html
= render
.call( this, entry
);
186 this.$element
.append( html
);
189 this.settings
.onComplete
.call( this.$element
[ 0 ], this.entries
);
194 // Simple JavaScript Templating (modified)
195 // John Resig - http://ejohn.org/ - MIT Licensed
196 // @see http://ejohn.org/blog/javascript-micro-templating/
198 tmpl
: function tmpl( str
, data
) {
200 var fn
= !/\W/.test( str
) ? this.tmplCache
[ str
] = this.tmplCache
[ str
] || this.tmpl( document
.getElementById( str
).innerHTML
) :
203 "var p=[],print=function(){p.push.apply(p,arguments);};" +
205 "with(obj){p.push('" +
207 .replace( /[\r\t\n]/g, " " )
208 .split( "<!" ).join( "\t" )
209 .replace( /((^|!>)[^\t]*)'/g, "$1\r" )
210 .replace( /\t=(.*?)!>/g, "',typeof $1 != 'undefined' ? $1 : '','" )
211 .split( "\t" ).join( "');" )
212 .split( "!>" ).join( "p.push('" )
213 .split( "\r" ).join( "\\'" ) +
214 "');}return p.join('');"
217 return data
? fn( data
) : fn
;
221 return $( this ).each( function( ) {
222 engine
.init( this, options
);