<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-app="angNewsApp">
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
<!-- Add your site or application content here -->
<div class="container">
<div ng-include="'nav.html'"></div>
<div ng-view=""></div>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-resource.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-cookies.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-sanitize.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-animate.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-touch.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
<script src="https://cdn.firebase.com/v0/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/angularfire/0.8.2/angularfire.min.js"></script>
<script src="https://cdn.firebase.com/js/simple-login/1.6.3/firebase-simple-login.js"></script>
<!-- App files -->
<script src="app.js"></script>
<script src="posts.controller.js"></script>
<script src="postview.controller.js"></script>
<script src="auth.controller.js"></script>
<script src="profile.controller.js"></script>
<script src="nav.controller.js"></script>
<script src="post.service.js"></script>
<script src="auth.service.js"></script>
<script src="user.service.js"></script>
<script src="url.filter.js"></script>
<script src="checkusername.directive.js"></script>
</div>
</body>
</html>
/* global app:true */
var app = angular.module('angNewsApp', [
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
'firebase'
])
.constant('FIREBASE_URL', 'https://angfirenews.firebaseio.com/');
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'posts.html',
controller: 'PostsCtrl'
})
.when('/posts/:postId', {
templateUrl: 'showpost.html',
controller: 'PostViewCtrl'
})
.when('/register', {
templateUrl: 'register.html',
controller: 'AuthCtrl'
})
.when('/login', {
templateUrl: 'login.html',
controller: 'AuthCtrl'
})
.when('/users/:username', {
templateUrl: 'profile.html',
controller: 'ProfileCtrl'
})
.otherwise({
redirectTo: '/'
});
});
app.controller('PostsCtrl', function($scope, $location, $routeParams, Post) {
if($location.path() === '/') {
$scope.posts = Post.all;
}
$scope.post = {url: 'http://', title: ''};
$scope.deletePost = function(post) {
Post.delete(post);
};
$scope.comments = Post.comments($routeParams.postId).$asArray();
$scope.addComment = function() {
Post.addComment($routeParams.postId, $scope.comment);
$scope.comment = '';
};
$scope.removeComment = function (comment) {
Post.deleteComment($scope.post, comment);
};
});
app.controller('PostViewCtrl', function($scope, $routeParams, Post) {
$scope.post = Post.find($routeParams.postId);
});
app.controller('AuthCtrl',
function ($scope, $location, Auth, User) {
if (Auth.signedIn()) {
$location.path('/');
}
$scope.$on('firebaseSimpleLogin:login', function() {
$location.path('/');
});
$scope.login = function() {
Auth.login($scope.user).then(function() {
$location.path('/');
}, function(error) {
$scope.error = error.toString();
});
};
});
app.controller('ProfileCtrl',
function ($scope, $routeParams, Post, User) {
$scope.user = User.findByUsername($routeParams.username);
$scope.posts = {};
$scope.commentedPosts = {};
$scope.comments = {};
$scope.user.$loaded(function () {
populatePosts();
populateComments();
});
function populatePosts () {
var posts = User.posts($routeParams.username).$asArray();
posts.$loaded(function (){
angular.forEach(posts, function (post){
$scope.posts[post.$id] = Post.find(post.$id);
});
});
}
function populateComments () {
var comments = User.comments($routeParams.username).$asArray();
comments.$loaded(function () {
angular.forEach(comments, function (comment) {
var post = Post.find(comment.$value);
post.$loaded(function () {
var postComments = Post.comments(comment.$value).$asObject();
postComments.$loaded(function () {
$scope.commentedPosts[comment.$id] = post;
$scope.comments[comment.$id] = postComments[comment.$id];
});
});
});
});
}
});
app.controller('NavCtrl', function($scope, $location, Post, Auth) {
$scope.post = {url: 'http://', title: ''};
$scope.submitPost = function () {
Post.create($scope.post).then(function (postId) {
$scope.post = {url: 'http://', title: ''};
$location.path('/posts/' + postId);
});
};
$scope.logout = function() {
Auth.logout();
};
});
app.factory('Post', function($firebase, FIREBASE_URL, User){
var ref = new Firebase(FIREBASE_URL + 'posts');
var posts = $firebase(ref).$asArray();
var Post = {
all: posts,
create: function(post) {
if(User.signedIn()) {
var user = User.getCurrent();
post.owner = user.username;
return posts.$add(post).then(function(ref) {
var postId = ref.name();
User.posts(user.username).$set(postId, postId);
return postId;
});
}
},
find: function(postId) {
return $firebase(ref.child(postId)).$asObject();
},
delete: function (post) {
if (User.signedIn()){
var user = User.getCurrent();
if (user.username === post.owner) {
posts.$remove(post).then(function () {
User.posts(user.username).$remove(post.$id);
console.log(post.$id);
});
}
}
},
comments: function(postId) {
return $firebase(new Firebase(FIREBASE_URL + 'comments/' + postId));
},
addComment: function (postId, comment) {
if (User.signedIn()) {
var user = User.getCurrent();
comment.username = user.username;
console.log('postID = ' + postId);
Post.comments(postId).$push(comment).then(function() {
var commentId = ref.name();
console.log('commentID = ' + commentId);
User.comments(user.username).$set(commentId, postId);
});
}
},
deleteComment: function (postId, comment) {
if (User.signedIn()) {
var user = User.findByUsername(comment.username);
var commentId = comment.$id;
Post.comments(postId).$remove(commentId).then(function () {
User.comments(user.username).$remove(commentId);
});
}
}
};
return Post;
});
app.factory('Auth',
function ($firebaseSimpleLogin, FIREBASE_URL, $rootScope) {
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseSimpleLogin(ref);
var Auth = {
signedIn: function () {
return auth.user !== null;
},
login: function(user) {
return auth.$login('password', user);
},
logout: function () {
auth.$logout();
}
};
$rootScope.signedIn = function () {
return Auth.signedIn();
};
return Auth;
});
app.factory('User', function ($firebase, FIREBASE_URL, $rootScope, $log) {
var ref = new Firebase(FIREBASE_URL + 'users');
var users = $firebase(ref);
function setCurrentUser(username) {
$rootScope.currentUser = User.findByUsername(username);
}
$rootScope.$on('$firebaseSimpleLogin:login', function (event, authUser) {
var query = $firebase(ref.startAt(authUser.uid).endAt(authUser.uid)).$asArray();
query.$loaded(function () {
setCurrentUser(query[0].username);
});
});
$rootScope.$on('$firebaseSimpleLogin:logout', function() {
delete $rootScope.currentUser;
});
var User = {
create: function (authUser, username) {
var user = $firebase(ref.child(username)).$asObject();
return user.$loaded(function() {
user.username = username;
/*jshint camelcase: false */
user.md5_hash = authUser.md5_hash;
user.$priority = authUser.uid;
user.$save();
});
$log.debug(users);
},
findByUsername: function (username) {
if (username) {
return $firebase(ref.child(username)).$asObject();
}
},
getCurrent: function () {
return $rootScope.currentUser;
},
signedIn: function () {
return $rootScope.currentUser !== undefined;
},
posts: function(username) {
return $firebase(new Firebase(FIREBASE_URL + 'user_posts/' + username));
},
comments: function (username) {
return $firebase(new Firebase(FIREBASE_URL + 'user_comments/' + username));
}
};
return User;
});
app.filter('hostnameFromUrl', function() {
return function(str) {
var url = document.createElement('a');
url.href = str;
return url.hostname;
};
});
angular.module('angNewsApp').directive('checkUsername', function(User) {
var usernameRegexp = /^[^.$\[\]#\/\s]+$/;
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.push(function(viewValue) {
if (usernameRegexp.test(viewValue)) {
User.findByUsername(viewValue).$loaded(function (user){
if (user.$value === null){
ctrl.$setValidity('taken', true);
ctrl.$setValidity('invalid', true);
} else {
ctrl.$setValidity('taken', false);
ctrl.$setValidity('invalid', true);
}
});
return viewValue;
} else {
ctrl.$setValidity('taken', true);
ctrl.$setValidity('invalid', false);
return viewValue;
}
});
}
};
});
<div class="container posts-page">
<div class="post row" ng-repeat="(postId, post) in posts">
<div class="col-xs-1">
</div>
<div class="col-md-9 col-xs-11">
<div class="info">
<a href="{{ post.url }}">
{{ post.title }}
<span class="url">({{post.url | hostnameFromUrl}})</span>
</a>
</div>
<div>
<span>{{ post.score || 0 }} votes</span>
—
<span>submitted by <a href="#/users/{{post.owner}}" >{{ post.owner }}</a></span>
—
<a href="#/posts/{{ post.$id }}">comments</a>
<a ng-click="deletePost(post)" ng-show="signedIn() && post.owner === currentUser.username">delete</a>
</div>
</div>
<div class="col-md-2">
</div>
</div>
</div>
<div class="container posts-page">
<div class="post row">
<div class="col-xs-1">
</div>
<div class="col-md-9 col-xs-11">
<div class="info">
<a href="{{ post.url }}">
{{ post.title }}
<span class="url">({{ post.url | hostnameFromUrl }})</span>
</a>
</div>
<div>
<span>submitted by <a href="#/users/{{ post.owner }}">{{ post.owner }}</a></span>
</div>
</div>
<div class="col-md-2">
</div>
</div>
<div ng-repeat="comment in comments" class="row cmt">
<div class="col-md-12">
<p>{{ comment.text }}</p>
<p class="author">posted by <a href="#/users/{{ comment.username }}">{{ comment.username }}</a></p>
</div>
</div>
<div class="cmt-form">
<div ng-hide="signedIn()">
<p><a href="#/login">Sign in</a> to post a comment</p>
</div>
<form ng-show="signedIn()">
<textarea ng-model="comment.text" placeholder="Post a Comment" class="form-control"></textarea><br />
<input type="submit" ng-click="addComment()" value="Post Comment" class="btn btn-primary" />
</form>
</div>
</div>
<div class="auth-forms">
<h2>Register</h2>
<form ng-submit="register()" name="form">
<div ng-show="error || form.username.$error">
<p ng-show="error" class="text-danger"></p>
<p ng-show="form.username.$error.taken" class="text-danger">Username is already taken.</p>
<p ng-show="form.username.$error.invalid" class="text-danger">Username contains invalid characters.</p>
</div>
<input type="email" ng-model="user.email" placeholder="Email" class="form-control"><br>
<input type="text" ng-model="user.username" placeholder="Username" name="username" check-username class="form-control"><br>
<input type="password" ng-model="user.password" placeholder="Password" class="form-control"><br>
<input type="submit" value="Register" class="btn btn-primary" />
</form>
</div>
<div class="auth-forms">
<h2>Log In</h2>
<form ng-submit="login()">
<p ng-show="error" class="text-danger">{{error}}</p>
<input type="email" ng-model="user.email" placeholder="Email" class="form-control"><br>
<input type="password" ng-model="user.password" placeholder="Password" class="form-control"><br>
<input type="submit" value="Log in" class="btn btn-primary" />
</form>
</div>
<div class="container profile">
<div class="row">
<div class="col-sm-1">
<img ng-src="http://www.gravatar.com/avatar/{{ user.md5_hash }}" class="prof-img" />
</div>
<div class="col-sm-10">
<span class="name">
{{ user.username }}
</span>
</div>
</div>
<div class="row">
<ul class="nav nav-tabs">
<li class="active"><a data-target="#submissions" data-toggle="tab">Submissions</a></li>
<li><a data-target="#comments" data-toggle="tab">Comments</a></li>
</ul>
</div>
</div>
<div class="tab-content">
<div ng-include="'views/posts.html'" class="tab-pane active" id="submissions" ng-controller="PostsCtrl"></div>
<div class="container posts-page tab-pane" id="comments">
<div class="post row" ng-repeat="(commentId, comment) in comments">
<div class="col-xs-1">
</div>
<div class="col-md-9 col-xs-11">
<div class="info">
<a href="{{ commentedPosts[commentId].url }}">{{ commentedPosts[commentId].title }}</a>
<span class="url">({{ commentedPosts[commentId].url | hostnameFromUrl }})</span>
</div>
<a href="#/posts/{{ commentedPosts[commentId].$id }}">comments</a>
<p>{{ comment.text }}</p>
</div>
<div class="col-md-2">
</div>
</div>
</div>
</div>
<nav class="navbar navbar-default" role="navigation">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">ng-news</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div ng-controller="NavCtrl" class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<form class="navbar-form navbar-left" role="search" ng-submit="submitPost()" ng-show="signedIn()">
<div class="form-group">
<input type="text" class="form-control" placeholder="Title" ng-model="post.title">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="Link" ng-model="post.url">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right" ng-show="signedIn()">
<li>
<a href="#/users/{{ currentUser.username }}">
<img ng-src="http://www.gravatar.com/avatar/{{ currentUser.md5_hash }} class="nav-pic" />
{{ currentUser.username }}
</a>
</li>
<li>
<a href="#" ng-click="logout()">Logout</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right" ng-hide="signedIn()">
<li>
<a href="#/login">Log In</a>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</nav>