1(function($) { 2 "use strict"; 3 4 var RSS = function(target, url, options, callback) { 5 this.target = target 6 this.url = url 7 this.html = [] 8 this.effectQueue = [] 9 10 this.options = $.extend({ 11 ssl: false, 12 limit: null, 13 key: null, 14 layoutTemplate: '<ul>{entries}</ul>', 15 entryTemplate: '<li><a href="{url}">[{author}@{date}] {title}</a><br/>{shortBodyPlain}</li>', 16 tokens: {}, 17 outputMode: 'json', 18 effect: 'show', 19 offsetStart: false, 20 offsetEnd: false, 21 error: function() { 22 console.log("jQuery RSS: url doesn't link to RSS-Feed"); 23 }, 24 success: function(){} 25 }, options || {}) 26 27 this.callback = callback || this.options.success 28 } 29 30 RSS.htmlTags = ["doctype", "html", "head", "title", "base", "link", "meta", "style", "script", "noscript", "body", "article", "nav", "aside", "section", "header", "footer", "h1-h6", "hgroup", "address", "p", "hr", "pre", "blockquote", "ol", "ul", "li", "dl", "dt", "dd", "figure", "figcaption", "div", "table", "caption", "thead", "tbody", "tfoot", "tr", "th", "td", "col", "colgroup", "form", "fieldset", "legend", "label", "input", "button", "select", "datalist", "optgroup", "option", "textarea", "keygen", "output", "progress", "meter", "details", "summary", "command", "menu", "del", "ins", "img", "iframe", "embed", "object", "param", "video", "audio", "source", "canvas", "track", "map", "area", "a", "em", "strong", "i", "b", "u", "s", "small", "abbr", "q", "cite", "dfn", "sub", "sup", "time", "code", "kbd", "samp", "var", "mark", "bdi", "bdo", "ruby", "rt", "rp", "span", "br", "wbr"] 31 32 RSS.prototype.load = function(callback) { 33 var apiProtocol = "http" + (this.options.ssl ? "s" : "") 34 , apiHost = apiProtocol + "://ajax.googleapis.com/ajax/services/feed/load" 35 , apiUrl = apiHost + "?v=1.0&output=" + this.options.outputMode + "&callback=?&q=" + encodeURIComponent(this.url) 36 37 // set limit to offsetEnd if offset has been set 38 if(this.options.offsetStart && this.options.offsetEnd) this.options.limit = this.options.offsetEnd; 39 if (this.options.limit != null) apiUrl += "&num=" + this.options.limit; 40 if (this.options.key != null) apiUrl += "&key=" + this.options.key; 41 42 $.getJSON(apiUrl, callback) 43 } 44 45 RSS.prototype.render = function() { 46 var self = this 47 48 this.load(function(data) { 49 try { 50 self.feed = data.responseData.feed 51 self.entries = data.responseData.feed.entries 52 } catch(e) { 53 self.entries = [] 54 self.feed = null 55 return self.options.error.call(self) 56 } 57 58 var html = self.generateHTMLForEntries() 59 60 self.target.append(html.layout) 61 62 if (html.entries.length !== 0) { 63 self.appendEntriesAndApplyEffects($("entries", html.layout), html.entries) 64 } 65 66 if (self.effectQueue.length > 0) { 67 self.executeEffectQueue(self.callback) 68 } else { 69 $.isFunction(self.callback) && self.callback.call(self); 70 } 71 }) 72 } 73 74 RSS.prototype.appendEntriesAndApplyEffects = function(target, entries) { 75 var self = this 76 77 $.each(entries, function(idx, entry) { 78 var $html = self.wrapContent(entry) 79 80 if(self.options.effect === 'show') { 81 target.before($html) 82 } else { 83 $html.css({ display: 'none' }) 84 target.before($html) 85 self.applyEffect($html, self.options.effect) 86 } 87 }) 88 89 target.remove() 90 } 91 92 RSS.prototype.generateHTMLForEntries = function() { 93 var self = this 94 , result = { 95 entries: [], 96 layout: null 97 } 98 99 $(this.entries).each(function() { 100 var entry = this, 101 offsetStart = self.options.offsetStart, 102 offsetEnd = self.options.offsetEnd; 103 // offset required 104 if(offsetStart && offsetEnd) { 105 if(index >= offsetStart && index <= offsetEnd) { 106 if(self.isRelevant(entry, result.entries)) { 107 var evaluatedString = self.evaluateStringForEntry(self.options.entryTemplate, entry) 108 result.entries.push(evaluatedString) 109 } 110 } 111 }else{ 112 // no offset 113 if(self.isRelevant(entry, result.entries)) { 114 var evaluatedString = self.evaluateStringForEntry(self.options.entryTemplate, entry) 115 result.entries.push(evaluatedString) 116 } 117 } 118 }) 119 120 if(!!this.options.entryTemplate) { 121 // we have an entryTemplate 122 result.layout = this.wrapContent(this.options.layoutTemplate.replace("{entries}", "<entries></entries>")) 123 } else { 124 // no entryTemplate available 125 result.layout = this.wrapContent("<div><entries></entries></div>") 126 } 127 128 return result 129 } 130 131 RSS.prototype.wrapContent = function(content) { 132 if($.trim(content).indexOf('<') !== 0) { 133 // the content has no html => create a surrounding div 134 return $("<div>" + content + "</div>") 135 } else { 136 // the content has html => don't touch it 137 return $(content) 138 } 139 } 140 141 RSS.prototype.applyEffect = function($element, effect, callback) { 142 var self = this 143 144 switch(effect) { 145 case 'slide': 146 $element.slideDown('slow', callback) 147 break 148 case 'slideFast': 149 $element.slideDown(callback) 150 break 151 case 'slideSynced': 152 self.effectQueue.push({ element: $element, effect: 'slide' }) 153 break 154 case 'slideFastSynced': 155 self.effectQueue.push({ element: $element, effect: 'slideFast' }) 156 break 157 } 158 } 159 160 RSS.prototype.executeEffectQueue = function(callback) { 161 var self = this 162 163 this.effectQueue.reverse() 164 165 var executeEffectQueueItem = function() { 166 var item = self.effectQueue.pop() 167 168 if(item) { 169 self.applyEffect(item.element, item.effect, executeEffectQueueItem) 170 } else { 171 callback && callback() 172 } 173 } 174 175 executeEffectQueueItem() 176 } 177 178 RSS.prototype.evaluateStringForEntry = function(string, entry) { 179 var result = string 180 , self = this 181 182 $(string.match(/(\{.*?\})/g)).each(function() { 183 var token = this.toString() 184 result = result.replace(token, self.getValueForToken(token, entry)) 185 }) 186 187 return result 188 } 189 190 RSS.prototype.isRelevant = function(entry, entries) { 191 var tokenMap = this.getTokenMap(entry) 192 193 if(this.options.filter) { 194 if(this.options.filterLimit && (this.options.filterLimit == entries.length)) { 195 return false 196 } else { 197 return this.options.filter(entry, tokenMap) 198 } 199 } else { 200 return true 201 } 202 } 203 204 RSS.prototype.getTokenMap = function(entry) { 205 if (!this.feedTokens) { 206 var feed = JSON.parse(JSON.stringify(this.feed)) 207 delete feed.entries 208 this.feedTokens = feed 209 } 210 211 return $.extend({ 212 feed: this.feedTokens, 213 url: entry.link, 214 author: entry.author, 215 date: entry.publishedDate, 216 title: entry.title, 217 body: entry.content, 218 shortBody: entry.contentSnippet, 219 220 bodyPlain: (function(entry) { 221 var result = entry.content 222 .replace(/<script[\\r\\\s\S]*<\/script>/mgi, '') 223 .replace(/<\/?[^>]+>/gi, '') 224 225 for(var i = 0; i < RSS.htmlTags.length; i++) { 226 result = result.replace(new RegExp('<' + RSS.htmlTags[i], 'gi'), '') 227 } 228 229 return result 230 })(entry), 231 232 shortBodyPlain: entry.contentSnippet.replace(/<\/?[^>]+>/gi, ''), 233 index: $.inArray(entry, this.entries), 234 totalEntries: this.entries.length, 235 236 teaserImage: (function(entry){ 237 try { return entry.content.match(/(<img.*?>)/gi)[0] } 238 catch(e) { return "" } 239 })(entry), 240 241 teaserImageUrl: (function(entry) { 242 try { return entry.content.match(/(<img.*?>)/gi)[0].match(/src="(.*?)"/)[1] } 243 catch(e) { return "" } 244 })(entry) 245 }, this.options.tokens) 246 } 247 248 RSS.prototype.getValueForToken = function(_token, entry) { 249 var tokenMap = this.getTokenMap(entry) 250 , token = _token.replace(/[\{\}]/g, '') 251 , result = tokenMap[token] 252 253 if(typeof result != 'undefined') 254 return ((typeof result == 'function') ? result(entry, tokenMap) : result) 255 else 256 throw new Error('Unknown token: ' + _token) 257 } 258 259 $.fn.rss = function(url, options, callback) { 260 new RSS(this, url, options, callback).render() 261 return this; //implement chaining 262 } 263 264})(jQuery)
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.