jasonbrooks / centos / centos.org

Forked from centos/centos.org 5 years ago
Clone

Blame assets/js/jquery.rss.js

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