Created
May 17, 2014 12:01
-
-
Save davidchang/078d74c3bc68e40dd4a9 to your computer and use it in GitHub Desktop.
Feed Reader version 2, using Angular/Underscore/Bootstrap CSS.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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