|
|
5b3906 |
(function ($) {
|
|
|
5b3906 |
'use strict';
|
|
|
5b3906 |
|
|
|
5b3906 |
var RSS = function (target, url, options, callback) {
|
|
|
5b3906 |
this.target = target;
|
|
|
5b3906 |
|
|
|
5b3906 |
this.url = url;
|
|
|
5b3906 |
this.html = [];
|
|
|
5b3906 |
this.effectQueue = [];
|
|
|
5b3906 |
|
|
|
5b3906 |
this.options = $.extend({
|
|
|
5b3906 |
ssl: false,
|
|
|
5b3906 |
host: 'www.feedrapp.info',
|
|
|
5b3906 |
limit: null,
|
|
|
5b3906 |
key: null,
|
|
|
5b3906 |
layoutTemplate: '',
|
|
|
5b3906 |
entryTemplate: '[{author}@{date}] {title} {shortBodyPlain}',
|
|
|
5b3906 |
tokens: {},
|
|
|
5b3906 |
outputMode: 'json',
|
|
|
5b3906 |
dateFormat: 'dddd MMM Do',
|
|
|
5b3906 |
dateLocale: 'en',
|
|
|
5b3906 |
effect: 'show',
|
|
|
5b3906 |
offsetStart: false,
|
|
|
5b3906 |
offsetEnd: false,
|
|
|
5b3906 |
error: function () {
|
|
|
5b3906 |
console.log('jQuery RSS: url doesn\'t link to RSS-Feed');
|
|
|
5b3906 |
},
|
|
|
5b3906 |
onData: function () {},
|
|
|
5b3906 |
success: function () {}
|
|
|
5b3906 |
}, options || {});
|
|
|
5b3906 |
|
|
|
5b3906 |
this.callback = callback || this.options.success;
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.htmlTags = [
|
|
|
5b3906 |
'doctype', 'html', 'head', 'title', 'base', 'link', 'meta', 'style', 'script', 'noscript',
|
|
|
5b3906 |
'body', 'article', 'nav', 'aside', 'section', 'header', 'footer', 'h1-h6', 'hgroup', 'address',
|
|
|
5b3906 |
'p', 'hr', 'pre', 'blockquote', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'figure', 'figcaption',
|
|
|
5b3906 |
'div', 'table', 'caption', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'col', 'colgroup',
|
|
|
5b3906 |
'form', 'fieldset', 'legend', 'label', 'input', 'button', 'select', 'datalist', 'optgroup',
|
|
|
5b3906 |
'option', 'textarea', 'keygen', 'output', 'progress', 'meter', 'details', 'summary', 'command',
|
|
|
5b3906 |
'menu', 'del', 'ins', 'img', 'iframe', 'embed', 'object', 'param', 'video', 'audio', 'source',
|
|
|
5b3906 |
'canvas', 'track', 'map', 'area', 'a', 'em', 'strong', 'i', 'b', 'u', 's', 'small', 'abbr', 'q',
|
|
|
5b3906 |
'cite', 'dfn', 'sub', 'sup', 'time', 'code', 'kbd', 'samp', 'var', 'mark', 'bdi', 'bdo', 'ruby',
|
|
|
5b3906 |
'rt', 'rp', 'span', 'br', 'wbr'
|
|
|
5b3906 |
];
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.load = function (callback) {
|
|
|
5b3906 |
var apiProtocol = 'http' + (this.options.ssl ? 's' : '');
|
|
|
5b3906 |
var apiHost = apiProtocol + '://' + this.options.host;
|
|
|
5b3906 |
var apiUrl = apiHost + '?callback=?&q=' + encodeURIComponent(this.url);
|
|
|
5b3906 |
|
|
|
5b3906 |
// set limit to offsetEnd if offset has been set
|
|
|
5b3906 |
if (this.options.offsetStart && this.options.offsetEnd) {
|
|
|
5b3906 |
this.options.limit = this.options.offsetEnd;
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
if (this.options.limit !== null) {
|
|
|
5b3906 |
apiUrl += '&num=' + this.options.limit;
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
if (this.options.key !== null) {
|
|
|
5b3906 |
apiUrl += '&key=' + this.options.key;
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
$.getJSON(apiUrl, callback);
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.render = function () {
|
|
|
5b3906 |
var self = this;
|
|
|
5b3906 |
|
|
|
5b3906 |
this.load(function (data) {
|
|
|
5b3906 |
try {
|
|
|
5b3906 |
self.feed = data.responseData.feed;
|
|
|
5b3906 |
self.entries = data.responseData.feed.entries;
|
|
|
5b3906 |
} catch (e) {
|
|
|
5b3906 |
self.entries = [];
|
|
|
5b3906 |
self.feed = null;
|
|
|
5b3906 |
return self.options.error.call(self);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
var html = self.generateHTMLForEntries();
|
|
|
5b3906 |
|
|
|
5b3906 |
self.target.append(html.layout);
|
|
|
5b3906 |
|
|
|
5b3906 |
if (html.entries.length !== 0) {
|
|
|
5b3906 |
if ($.isFunction(self.options.onData)) {
|
|
|
5b3906 |
self.options.onData.call(self);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
var container = $(html.layout).is('entries') ? html.layout : $('entries', html.layout);
|
|
|
5b3906 |
|
|
|
5b3906 |
self.appendEntriesAndApplyEffects(container, html.entries);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
if (self.effectQueue.length > 0) {
|
|
|
5b3906 |
self.executeEffectQueue(self.callback);
|
|
|
5b3906 |
} else if ($.isFunction(self.callback)) {
|
|
|
5b3906 |
self.callback.call(self);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
});
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.appendEntriesAndApplyEffects = function (target, entries) {
|
|
|
5b3906 |
var self = this;
|
|
|
5b3906 |
|
|
|
5b3906 |
$.each(entries, function (idx, entry) {
|
|
|
5b3906 |
var $html = self.wrapContent(entry);
|
|
|
5b3906 |
|
|
|
5b3906 |
if (self.options.effect === 'show') {
|
|
|
5b3906 |
target.before($html);
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
$html.css({ display: 'none' });
|
|
|
5b3906 |
target.before($html);
|
|
|
5b3906 |
self.applyEffect($html, self.options.effect);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
});
|
|
|
5b3906 |
|
|
|
5b3906 |
target.remove();
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.generateHTMLForEntries = function () {
|
|
|
5b3906 |
var self = this;
|
|
|
5b3906 |
var result = { entries: [], layout: null };
|
|
|
5b3906 |
|
|
|
5b3906 |
$(this.entries).each(function () {
|
|
|
5b3906 |
var entry = this;
|
|
|
5b3906 |
var offsetStart = self.options.offsetStart;
|
|
|
5b3906 |
var offsetEnd = self.options.offsetEnd;
|
|
|
5b3906 |
var evaluatedString;
|
|
|
5b3906 |
|
|
|
5b3906 |
// offset required
|
|
|
5b3906 |
if (offsetStart && offsetEnd) {
|
|
|
5b3906 |
if (index >= offsetStart && index <= offsetEnd) {
|
|
|
5b3906 |
if (self.isRelevant(entry, result.entries)) {
|
|
|
5b3906 |
evaluatedString = self.evaluateStringForEntry(
|
|
|
5b3906 |
self.options.entryTemplate, entry
|
|
|
5b3906 |
);
|
|
|
5b3906 |
|
|
|
5b3906 |
result.entries.push(evaluatedString);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
}
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
// no offset
|
|
|
5b3906 |
if (self.isRelevant(entry, result.entries)) {
|
|
|
5b3906 |
evaluatedString = self.evaluateStringForEntry(
|
|
|
5b3906 |
self.options.entryTemplate, entry
|
|
|
5b3906 |
);
|
|
|
5b3906 |
|
|
|
5b3906 |
result.entries.push(evaluatedString);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
}
|
|
|
5b3906 |
});
|
|
|
5b3906 |
|
|
|
5b3906 |
if (!!this.options.entryTemplate) {
|
|
|
5b3906 |
// we have an entryTemplate
|
|
|
5b3906 |
result.layout = this.wrapContent(
|
|
|
5b3906 |
this.options.layoutTemplate.replace('{entries}', '<entries></entries>')
|
|
|
5b3906 |
);
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
// no entryTemplate available
|
|
|
5b3906 |
result.layout = this.wrapContent('<entries></entries> ');
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
return result;
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.wrapContent = function (content) {
|
|
|
5b3906 |
if (($.trim(content).indexOf('<') !== 0)) {
|
|
|
5b3906 |
// the content has no html => create a surrounding div
|
|
|
5b3906 |
return $('' + content + ' ');
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
// the content has html => don't touch it
|
|
|
5b3906 |
return $(content);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.applyEffect = function ($element, effect, callback) {
|
|
|
5b3906 |
var self = this;
|
|
|
5b3906 |
|
|
|
5b3906 |
switch (effect) {
|
|
|
5b3906 |
case 'slide':
|
|
|
5b3906 |
$element.slideDown('slow', callback);
|
|
|
5b3906 |
break;
|
|
|
5b3906 |
case 'slideFast':
|
|
|
5b3906 |
$element.slideDown(callback);
|
|
|
5b3906 |
break;
|
|
|
5b3906 |
case 'slideSynced':
|
|
|
5b3906 |
self.effectQueue.push({ element: $element, effect: 'slide' });
|
|
|
5b3906 |
break;
|
|
|
5b3906 |
case 'slideFastSynced':
|
|
|
5b3906 |
self.effectQueue.push({ element: $element, effect: 'slideFast' });
|
|
|
5b3906 |
break;
|
|
|
5b3906 |
}
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.executeEffectQueue = function (callback) {
|
|
|
5b3906 |
var self = this;
|
|
|
5b3906 |
|
|
|
5b3906 |
this.effectQueue.reverse();
|
|
|
5b3906 |
|
|
|
5b3906 |
var executeEffectQueueItem = function () {
|
|
|
5b3906 |
var item = self.effectQueue.pop();
|
|
|
5b3906 |
|
|
|
5b3906 |
if (item) {
|
|
|
5b3906 |
self.applyEffect(item.element, item.effect, executeEffectQueueItem);
|
|
|
5b3906 |
} else if (callback) {
|
|
|
5b3906 |
callback();
|
|
|
5b3906 |
}
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
executeEffectQueueItem();
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.evaluateStringForEntry = function (string, entry) {
|
|
|
5b3906 |
var result = string;
|
|
|
5b3906 |
var self = this;
|
|
|
5b3906 |
|
|
|
5b3906 |
$(string.match(/(\{.*?\})/g)).each(function () {
|
|
|
5b3906 |
var token = this.toString();
|
|
|
5b3906 |
|
|
|
5b3906 |
result = result.replace(token, self.getValueForToken(token, entry));
|
|
|
5b3906 |
});
|
|
|
5b3906 |
|
|
|
5b3906 |
return result;
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.isRelevant = function (entry, entries) {
|
|
|
5b3906 |
var tokenMap = this.getTokenMap(entry);
|
|
|
5b3906 |
|
|
|
5b3906 |
if (this.options.filter) {
|
|
|
5b3906 |
if (this.options.filterLimit && (this.options.filterLimit === entries.length)) {
|
|
|
5b3906 |
return false;
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
return this.options.filter(entry, tokenMap);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
return true;
|
|
|
5b3906 |
}
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.getFormattedDate = function (dateString) {
|
|
|
5b3906 |
// If a custom formatting function is provided, use that.
|
|
|
5b3906 |
if (this.options.dateFormatFunction) {
|
|
|
5b3906 |
return this.options.dateFormatFunction(dateString);
|
|
|
5b3906 |
} else if (typeof moment !== 'undefined') {
|
|
|
5b3906 |
// If moment.js is available and dateFormatFunction is not overriding it,
|
|
|
5b3906 |
// use it to format the date.
|
|
|
5b3906 |
var date = moment(new Date(dateString));
|
|
|
5b3906 |
|
|
|
5b3906 |
if (date.locale) {
|
|
|
5b3906 |
date = date.locale(this.options.dateLocale);
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
date = date.lang(this.options.dateLocale);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
return date.format(this.options.dateFormat);
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
// If all else fails, just use the date as-is.
|
|
|
5b3906 |
return dateString;
|
|
|
5b3906 |
}
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.getTokenMap = function (entry) {
|
|
|
5b3906 |
if (!this.feedTokens) {
|
|
|
5b3906 |
var feed = JSON.parse(JSON.stringify(this.feed));
|
|
|
5b3906 |
|
|
|
5b3906 |
delete feed.entries;
|
|
|
5b3906 |
this.feedTokens = feed;
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
return $.extend({
|
|
|
5b3906 |
feed: this.feedTokens,
|
|
|
5b3906 |
url: entry.link,
|
|
|
5b3906 |
author: entry.author,
|
|
|
5b3906 |
date: this.getFormattedDate(entry.publishedDate),
|
|
|
5b3906 |
title: entry.title,
|
|
|
5b3906 |
body: entry.content,
|
|
|
5b3906 |
shortBody: entry.contentSnippet,
|
|
|
5b3906 |
|
|
|
5b3906 |
bodyPlain: (function (entry) {
|
|
|
5b3906 |
var result = entry.content
|
|
|
5b3906 |
.replace(/<script[\\r\\\s\S]*<\/script>/mgi, '')
|
|
|
5b3906 |
.replace(/<\/?[^>]+>/gi, '');
|
|
|
5b3906 |
|
|
|
5b3906 |
for (var i = 0; i < RSS.htmlTags.length; i++) {
|
|
|
5b3906 |
result = result.replace(new RegExp('<' + RSS.htmlTags[i], 'gi'), '');
|
|
|
5b3906 |
}
|
|
|
5b3906 |
|
|
|
5b3906 |
return result;
|
|
|
5b3906 |
})(entry),
|
|
|
5b3906 |
|
|
|
5b3906 |
shortBodyPlain: entry.contentSnippet.replace(/<\/?[^>]+>/gi, ''),
|
|
|
5b3906 |
index: $.inArray(entry, this.entries),
|
|
|
5b3906 |
totalEntries: this.entries.length,
|
|
|
5b3906 |
|
|
|
5b3906 |
teaserImage: (function (entry) {
|
|
|
5b3906 |
try {
|
|
|
5b3906 |
return entry.content.match(/(<img.*?>)/gi)[0];
|
|
|
5b3906 |
}
|
|
|
5b3906 |
catch (e) {
|
|
|
5b3906 |
return '';
|
|
|
5b3906 |
}
|
|
|
5b3906 |
})(entry),
|
|
|
5b3906 |
|
|
|
5b3906 |
teaserImageUrl: (function (entry) {
|
|
|
5b3906 |
try {
|
|
|
5b3906 |
return entry.content.match(/(<img.*?>)/gi)[0].match(/src="(.*?)"/)[1];
|
|
|
5b3906 |
}
|
|
|
5b3906 |
catch (e) {
|
|
|
5b3906 |
return '';
|
|
|
5b3906 |
}
|
|
|
5b3906 |
})(entry)
|
|
|
5b3906 |
}, this.options.tokens);
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
RSS.prototype.getValueForToken = function (_token, entry) {
|
|
|
5b3906 |
var tokenMap = this.getTokenMap(entry);
|
|
|
5b3906 |
var token = _token.replace(/[\{\}]/g, '');
|
|
|
5b3906 |
var result = tokenMap[token];
|
|
|
5b3906 |
|
|
|
5b3906 |
if (typeof result !== 'undefined') {
|
|
|
5b3906 |
return ((typeof result === 'function') ? result(entry, tokenMap) : result);
|
|
|
5b3906 |
} else {
|
|
|
5b3906 |
throw new Error('Unknown token: ' + _token + ', url:' + this.url);
|
|
|
5b3906 |
}
|
|
|
5b3906 |
};
|
|
|
5b3906 |
|
|
|
5b3906 |
$.fn.rss = function (url, options, callback) {
|
|
|
5b3906 |
new RSS(this, url, options, callback).render();
|
|
|
5b3906 |
return this; // Implement chaining
|
|
|
5b3906 |
};
|
|
|
5b3906 |
})(jQuery);
|