Skip to content

Instantly share code, notes, and snippets.

@davidchang
Last active December 5, 2016 17:26
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save davidchang/4441416 to your computer and use it in GitHub Desktop.
Save davidchang/4441416 to your computer and use it in GitHub Desktop.
Feed Reader version 1, using Angular/Underscore/Bootstrap CSS.
<!doctype html>
<html ng-app>
<head>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet">
<style>
.title {
cursor: pointer;
font-weight: bold;
font-size: 24.5px;
line-height: 40px;
margin: 10px 0px;
}
.markRead {
margin-left: 5px;
font-size: 11px;
cursor: pointer;
}
.read-true, .read-true a {
color: #CCC;
}
#rssFeed {
width: 720px;
}
.margin-top {
margin-top: 25px;
}
.margin-bottom {
margin-bottom: 15px;
}
body.dark {
background-color: #222;
color: #EEE;
}
</style>
</head>
<body>
<div ng-controller="RssFeedCtrl">
<div class='container-fluid margin-top'>
<div class='span12'>
<form class="form-horizontal">
<div class="control-group">
<input id='rssFeed' ng-model='rssFeed' type="text" placeholder="RSS Feed">
<button id='update' type="submit" class="btn" ng-click="updateModel()">Load feed</button>
</div>
</form>
</div>
</div>
<div ng-show='existingArticles()' class='container-fluid margin-bottom'>
<div class='span12 margin-bottom'>
<button class="btn" ng-click="markAll()">Mark all as <span ng-show='allAreRead()'>un</span>read</button>
<button class="btn" ng-click="clearCompleted()">Clear Read</button>
<button class="btn" ng-click="showOrHideAll()"><span>Toggle Headlines/Content</span></button>
<button class="btn" id='toggleTheme'><span>Toggle Dark/Light Theme</span></button>
</div>
<div ng-hide='article.cleared' class='span12 read-{{article.read}}' ng-repeat="article in articles">
<span ng-click='toggleShow(article)' class='title'>{{article.title}}</span>
<span><a href='{{article.link}}' target='_blank'>{{article.shortLink}}</a></span>
<span ng-click="markAsRead(article)" class='markRead'>(Mark as <span ng-show='article.read'>un</span>read)</span>
<div ng-show='article.show' class='content'>{{article.content}}</div>
</div>
</div>
<div ng-hide='existingArticles()' class='container-fluid'>
<div ngclass='span12'>
You may have read all of the articles... :/ I'll try to load some more...
</div>
</div>
</div>
<script src='//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.3/underscore-min.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.3/angular.min.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js'></script>
<script>
function RssFeedCtrl($scope) {
$scope.articles = [ ];
$scope.rssFeed = 'http://hnapp.com/api/items/rss/a817dd49f3fe75b6fc2764bd98b714f7';
$scope.originalRssFeed = 'http://hnapp.com/api/items/rss/a817dd49f3fe75b6fc2764bd98b714f7';
$scope.existingArticles = function() {
return _.find($scope.articles, function(a) { return !a.cleared}) != null;
};
$scope.allAreRead = function() {
return _.every($scope.articles, function(a) { return a.read; });
};
$scope.showOrHideAll = function() {
var markAsHide = _.every($scope.articles, function(a) { return a.show; });
_.each($scope.articles, function(el, index, list) { el.show = !markAsHide; });
};
$scope.clearCompleted = function () {
_.each(_.where($scope.articles, { read: true }), function(a) { a.cleared = true; });
};
$scope.toggleShow = function(article) {
article.show = !article.show;
};
$scope.markAsRead = function(article) {
article.read = !article.read;
};
$scope.markAll = function() {
var markAsUnread = $scope.allAreRead();
_.each($scope.articles, function(el, index, list) { el.read = !markAsUnread; });
};
var hostname = (function () {
var a = document.createElement('a');
return function (url) {
a.href = url;
return a.hostname;
}
})();
var parseEntry = function(el) {
var date = el.publishedDate || el.pubDate;
var content = el.content || el.description;
return { title: el.title, content: content, read: false, date: date, link: el.link, shortLink: hostname(el.link) };
}
var parseRSS = function(url, callback) {
$.ajax({
url: '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=?&q=' + encodeURIComponent(url),
dataType: 'json',
success: callback
});
}
$scope.updateModel = function() {
parseRSS($scope.rssFeed, function(data) {
if(data == null)
return;
var mostRecentDate = null;
if($scope.articles.length && $scope.rssFeed == $scope.originalRssFeed)
mostRecentDate = $scope.articles[0].date;
var entries = _.map(data.responseData.feed.entries, function(el) { return parseEntry(el); });
if(mostRecentDate != null) {
entries = _.filter(entries, function(el) { return el.date < mostRecentDate; });
}
if($scope.rssFeed != $scope.originalRssFeed) {
$scope.articles = entries;
$scope.originalRssFeed = $scope.rssFeed;
}
else
$scope.articles = _.union($scope.articles, entries);
$scope.$apply(function() {
$scope.articles = _.sortBy($scope.articles, function(el) { return el.date; });
});
});
};
}
$(function() {
var $update = $('#update');
$update.click();
//then call every 30 secs
var timeout = 30000;
setInterval(function() {
if(document.activeElement.nodeName != 'INPUT' && document.activeElement.id != 'rssFeed')
$update.click();
}, timeout);
var $body = $('body');
$('#toggleTheme').click(function() {
$body.toggleClass('dark');
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment