PageSourceSearch

https://www.francoabruzzo.it/jscripts/jquery.rss.js

js francoabruzzo.it collected 2026-10-02 11:19:52 UTC 10,177 bytes, 333 lines download raw bytes

1(function ($) {
2  'use strict';
3
4  var RSS = function (target, url, options, callback) {
5    this.target       = target;
6
7    this.url          = url;
8    this.html         = [];
9    this.effectQueue  = [];
10
11    this.options = $.extend({
12      ssl: false,
13      host: 'www.feedrapp.info',
14      limit: null,
15      key: null,
16      layoutTemplate: '<ul>{entries}</ul>',
17      entryTemplate: '<li><a href="{url}">[{author}@{date}] {title}</a><br/>{shortBodyPlain}</li>',
18      tokens: {},
19      outputMode: 'json',
20      dateFormat: 'dddd MMM Do',
21      dateLocale: 'en',
22      effect: 'show',
23      offsetStart: false,
24      offsetEnd: false,
25      error: function () {
26        console.log('jQuery RSS: url doesn\'t link to RSS-Feed');
27      },
28      onData: function () {},
29      success: function () {}
30    }, options || {});
31
32    this.callback = callback || this.options.success;
33  };
34
35  RSS.htmlTags = [
36    'doctype', 'html', 'head', 'title', 'base', 'link', 'meta', 'style', 'script', 'noscript',
37    'body', 'article', 'nav', 'aside', 'section', 'header', 'footer', 'h1-h6', 'hgroup', 'address',
38    'p', 'hr', 'pre', 'blockquote', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'figure', 'figcaption',
39    'div', 'table', 'caption', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'col', 'colgroup',
40    'form', 'fieldset', 'legend', 'label', 'input', 'button', 'select', 'datalist', 'optgroup',
41    'option', 'textarea', 'keygen', 'output', 'progress', 'meter', 'details', 'summary', 'command',
42    'menu', 'del', 'ins', 'img', 'iframe', 'embed', 'object', 'param', 'video', 'audio', 'source',
43    'canvas', 'track', 'map', 'area', 'a', 'em', 'strong', 'i', 'b', 'u', 's', 'small', 'abbr', 'q',
44    'cite', 'dfn', 'sub', 'sup', 'time', 'code', 'kbd', 'samp', 'var', 'mark', 'bdi', 'bdo', 'ruby',
45    'rt', 'rp', 'span', 'br', 'wbr'
46  ];
47
48  RSS.prototype.load = function (callback) {
49    var apiProtocol = 'http' + (this.options.ssl ? 's' : '');
50    var apiHost     = apiProtocol + '://' + this.options.host;
51    var apiUrl      = apiHost + '?callback=?&q=' + encodeURIComponent(this.url);
52
53    // set limit to offsetEnd if offset has been set
54    if (this.options.offsetStart && this.options.offsetEnd) {
55      this.options.limit = this.options.offsetEnd;
56    }
57
58    if (this.options.limit !== null) {
59      apiUrl += '&num=' + this.options.limit;
60    }
61
62    if (this.options.key !== null) {
63      apiUrl += '&key=' + this.options.key;
64    }
65
66    $.getJSON(apiUrl, callback);
67  };
68
69  RSS.prototype.render = function () {
70    var self = this;
71
72    this.load(function (data) {
73      try {
74        self.feed    = data.responseData.feed;
75        self.entries = data.responseData.feed.entries;
76      } catch (e) {
77        self.entries = [];
78        self.feed    = null;
79        return self.options.error.call(self);
80      }
81
82      var html = self.generateHTMLForEntries();
83
84      self.target.append(html.layout);
85
86      if (html.entries.length !== 0) {
87        if ($.isFunction(self.options.onData)) {
88          self.options.onData.call(self);
89        }
90
91        var container = $(html.layout).is('entries') ? html.layout : $('entries', html.layout);
92
93        self.appendEntriesAndApplyEffects(container, html.entries);
94      }
95
96      if (self.effectQueue.length > 0) {
97        self.executeEffectQueue(self.callback);
98      } else if ($.isFunction(self.callback)) {
99        self.callback.call(self);
100      }
101    });
102  };
103
104  RSS.prototype.appendEntriesAndApplyEffects = function (target, entries) {
105    var self = this;
106
107    $.each(entries, function (idx, entry) {
108      var $html = self.wrapContent(entry);
109
110      if (self.options.effect === 'show') {
111        target.before($html);
112      } else {
113        $html.css({ display: 'none' });
114        target.before($html);
115        self.applyEffect($html, self.options.effect);
116      }
117    });
118
119    target.remove();
120  };
121
122  RSS.prototype.generateHTMLForEntries = function () {
123    var self   = this;
124    var result = { entries: [], layout: null };
125
126    $(this.entries).each(function () {
127      var entry       = this;
128      var offsetStart = self.options.offsetStart;
129      var offsetEnd   = self.options.offsetEnd;
130      var evaluatedString;
131
132      // offset required
133      if (offsetStart && offsetEnd) {
134        if (index >= offsetStart && index <= offsetEnd) {
135          if (self.isRelevant(entry, result.entries)) {
136            evaluatedString = self.evaluateStringForEntry(
137              self.options.entryTemplate, entry
138            );
139
140            result.entries.push(evaluatedString);
141          }
142        }
143      } else {
144        // no offset
145        if (self.isRelevant(entry, result.entries)) {
146          evaluatedString = self.evaluateStringForEntry(
147            self.options.entryTemplate, entry
148          );
149
150          result.entries.push(evaluatedString);
151        }
152      }
153    });
154
155    if (!!this.options.entryTemplate) {
156      // we have an entryTemplate
157      result.layout = this.wrapContent(
158        this.options.layoutTemplate.replace('{entries}', '<entries></entries>')
159      );
160    } else {
161      // no entryTemplate available
162      result.layout = this.wrapContent('<div><entries></entries></div>');
163    }
164
165    return result;
166  };
167
168  RSS.prototype.wrapContent = function (content) {
169    if (($.trim(content).indexOf('<') !== 0)) {
170      // the content has no html => create a surrounding div
171      return $('<div>' + content + '</div>');
172    } else {
173      // the content has html => don't touch it
174      return $(content);
175    }
176  };
177
178  RSS.prototype.applyEffect = function ($element, effect, callback) {
179    var self = this;
180
181    switch (effect) {
182      case 'slide':
183        $element.slideDown('slow', callback);
184        break;
185      case 'slideFast':
186        $element.slideDown(callback);
187        break;
188      case 'slideSynced':
189        self.effectQueue.push({ element: $element, effect: 'slide' });
190        break;
191      case 'slideFastSynced':
192        self.effectQueue.push({ element: $element, effect: 'slideFast' });
193        break;
194    }
195  };
196
197  RSS.prototype.executeEffectQueue = function (callback) {
198    var self = this;
199
200    this.effectQueue.reverse();
201
202    var executeEffectQueueItem = function () {
203      var item = self.effectQueue.pop();
204
205      if (item) {
206        self.applyEffect(item.element, item.effect, executeEffectQueueItem);
207      } else if (callback) {
208        callback();
209      }
210    };
211
212    executeEffectQueueItem();
213  };
214
215  RSS.prototype.evaluateStringForEntry = function (string, entry) {
216    var result = string;
217    var self   = this;
218
219    $(string.match(/(\{.*?\})/g)).each(function () {
220      var token = this.toString();
221
222      result = result.replace(token, self.getValueForToken(token, entry));
223    });
224
225    return result;
226  };
227
228  RSS.prototype.isRelevant = function (entry, entries) {
229    var tokenMap = this.getTokenMap(entry);
230
231    if (this.options.filter) {
232      if (this.options.filterLimit && (this.options.filterLimit === entries.length)) {
233        return false;
234      } else {
235        return this.options.filter(entry, tokenMap);
236      }
237    } else {
238      return true;
239    }
240  };
241
242  RSS.prototype.getFormattedDate = function (dateString) {
243    // If a custom formatting function is provided, use that.
244    if (this.options.dateFormatFunction) {
245      return this.options.dateFormatFunction(dateString);
246    } else if (typeof moment !== 'undefined') {
247      // If moment.js is available and dateFormatFunction is not overriding it,
248      // use it to format the date.
249      var date = moment(new Date(dateString));
250
251      if (date.locale) {
252        date = date.locale(this.options.dateLocale);
253      } else {
254        date = date.lang(this.options.dateLocale);
255      }
256
257      return date.format(this.options.dateFormat);
258    } else {
259      // If all else fails, just use the date as-is.
260      return dateString;
261    }
262  };
263
264  RSS.prototype.getTokenMap = function (entry) {
265    if (!this.feedTokens) {
266      var feed = JSON.parse(JSON.stringify(this.feed));
267
268      delete feed.entries;
269      this.feedTokens = feed;
270    }
271
272    return $.extend({
273      feed:      this.feedTokens,
274      url:       entry.link,
275      author:    entry.author,
276      date:      this.getFormattedDate(entry.publishedDate),
277      title:     entry.title,
278      body:      entry.content,
279      shortBody: entry.contentSnippet,
280
281      bodyPlain: (function (entry) {
282        var result = entry.content
283          .replace(/<script[\\r\\\s\S]*<\/script>/mgi, '')
284          .replace(/<\/?[^>]+>/gi, '');
285
286        for (var i = 0; i < RSS.htmlTags.length; i++) {
287          result = result.replace(new RegExp('<' + RSS.htmlTags[i], 'gi'), '');
288        }
289
290        return result;
291      })(entry),
292
293      shortBodyPlain: entry.contentSnippet.replace(/<\/?[^>]+>/gi, ''),
294      index:          $.inArray(entry, this.entries),
295      totalEntries:   this.entries.length,
296
297      teaserImage:    (function (entry) {
298        try {
299          return entry.content.match(/(<img.*?>)/gi)[0];
300        }
301        catch (e) {
302          return '';
303        }
304      })(entry),
305
306      teaserImageUrl: (function (entry) {
307        try {
308          return entry.content.match(/(<img.*?>)/gi)[0].match(/src="(.*?)"/)[1];
309        }
310        catch (e) {
311          return '';
312        }
313      })(entry)
314    }, this.options.tokens);
315  };
316
317  RSS.prototype.getValueForToken = function (_token, entry) {
318    var tokenMap = this.getTokenMap(entry);
319    var token    = _token.replace(/[\{\}]/g, '');
320    var result   = tokenMap[token];
321
322    if (typeof result !== 'undefined') {
323      return ((typeof result === 'function') ? result(entry, tokenMap) : result);
324    } else {
325      throw new Error('Unknown token: ' + _token + ', url:' + this.url);
326    }
327  };
328
329  $.fn.rss = function (url, options, callback) {
330    new RSS(this, url, options, callback).render();
331    return this; // Implement chaining
332  };
333})(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.