Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@davidchang
Created May 17, 2014 12:01
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save davidchang/078d74c3bc68e40dd4a9 to your computer and use it in GitHub Desktop.
Save davidchang/078d74c3bc68e40dd4a9 to your computer and use it in GitHub Desktop.
Feed Reader version 2, using Angular/Underscore/Bootstrap CSS.
<!doctype html>
<html ng-app="feedReaderApp">
<head>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.2/css/bootstrap.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 ng-class="{dark : darkTheme}" 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' ng-focus="rssFeedFocused=true" ng-blur="rssFeedFocused=false" 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" ng-click="darkTheme = !darkTheme"><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='article.show = !article.show' class='title'>{{article.title}}</span>
<span><a href='{{article.link}}' target='_blank'>{{article.shortLink}}</a></span>
<span ng-click="article.read = !article.read" 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>
<script src='//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js'></script>
<script>
angular.module('feedReaderApp', [])
.controller('RssFeedCtrl', [
'$http', '$interval', '$scope',
function($http, $interval, $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.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) {
return {
title : el.title,
content : el.content || el.description,
read : false,
date : el.publishedDate || el.pubDate,
link : el.link,
shortLink : hostname(el.link)
};
};
var parseRSS = function(url) {
return $http.jsonp('//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url));
};
$scope.updateModel = function() {
parseRSS($scope.rssFeed)
.then(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.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.articles = _.sortBy($scope.articles, function(el) { return el.date; });
});
};
// update initially
$scope.updateModel();
//then update every 30 secs
$interval(function() {
if ($scope.rssFeedFocused) {
$scope.updateModel();
}
}, 30000);
}]);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment