Professional Documents
Culture Documents
/**
* Saves a new post to the Firebase DB.
*/
// [START write_fan_out]
function writeNewPost(uid, username, picture, title, body) {
// A post entry.
var postData = {
author: username,
uid: uid,
body: body,
title: title,
starCount: 0,
authorPic: picture
};
// Write the new post's data simultaneously in the posts list and the user's post
list.
var updates = {};
updates['/posts/' + newPostKey] = postData;
updates['/user-posts/' + uid + '/' + newPostKey] = postData;
return firebase.database().ref().update(updates);
}
// [END write_fan_out]
/**
* Star/unstar post.
*/
// [START post_stars_transaction]
function toggleStar(postRef, uid) {
postRef.transaction(function(post) {
if (post) {
if (post.stars && post.stars[uid]) {
post.starCount--;
post.stars[uid] = null;
} else {
post.starCount++;
if (!post.stars) {
post.stars = {};
}
post.stars[uid] = true;
}
}
return post;
});
}
// [END post_stars_transaction]
/**
* Creates a post element.
*/
function createPostElement(postId, title, text, author, authorId, authorPic) {
var uid = firebase.auth().currentUser.uid;
var html =
'<div class="post post-' + postId + ' mdl-cell mdl-cell--12-col ' +
'mdl-cell--6-col-tablet mdl-cell--4-col-desktop mdl-grid mdl-
grid--no-spacing">' +
'<div class="mdl-card mdl-shadow--2dp">' +
'<div class="mdl-card__title mdl-color--light-blue-600 mdl-color-text--
white">' +
'<h4 class="mdl-card__title-text"></h4>' +
'</div>' +
'<div class="header">' +
'<div>' +
'<div class="avatar"></div>' +
'<div class="username mdl-color-text--black"></div>' +
'</div>' +
'</div>' +
'<span class="star">' +
'<div class="not-starred material-icons">star_border</div>' +
'<div class="starred material-icons">star</div>' +
'<div class="star-count">0</div>' +
'</span>' +
'<div class="text"></div>' +
'<div class="comments-container"></div>' +
'<form class="add-comment" action="#">' +
'<div class="mdl-textfield mdl-js-textfield">' +
'<input class="mdl-textfield__input new-comment" type="text">' +
'<label class="mdl-textfield__label">Comment...</label>' +
'</div>' +
'</form>' +
'</div>' +
'</div>';
// Set values.
postElement.getElementsByClassName('text')[0].innerText = text;
postElement.getElementsByClassName('mdl-card__title-text')[0].innerText = title;
postElement.getElementsByClassName('username')[0].innerText = author ||
'Anonymous';
postElement.getElementsByClassName('avatar')[0].style.backgroundImage = 'url("' +
(authorPic || './silhouette.jpg') + '")';
commentsRef.on('child_changed', function(data) {
setCommentValues(postElement, data.key, data.val().text, data.val().author);
});
commentsRef.on('child_removed', function(data) {
deleteComment(postElement, data.key);
});
// [END child_event_listener_recycler]
return postElement;
}
/**
* Writes a new comment for the given post.
*/
function createNewComment(postId, username, uid, text) {
firebase.database().ref('post-comments/' + postId).push({
text: text,
author: username,
uid: uid
});
}
/**
* Updates the starred status of the post.
*/
function updateStarredByCurrentUser(postElement, starred) {
if (starred) {
postElement.getElementsByClassName('starred')[0].style.display = 'inline-
block';
postElement.getElementsByClassName('not-starred')[0].style.display = 'none';
} else {
postElement.getElementsByClassName('starred')[0].style.display = 'none';
postElement.getElementsByClassName('not-starred')[0].style.display = 'inline-
block';
}
}
/**
* Updates the number of stars displayed for a post.
*/
function updateStarCount(postElement, nbStart) {
postElement.getElementsByClassName('star-count')[0].innerText = nbStart;
}
/**
* Creates a comment element and adds it to the given postElement.
*/
function addCommentElement(postElement, id, text, author) {
var comment = document.createElement('div');
comment.classList.add('comment-' + id);
comment.innerHTML = '<span class="username"></span><span
class="comment"></span>';
comment.getElementsByClassName('comment')[0].innerText = text;
comment.getElementsByClassName('username')[0].innerText = author || 'Anonymous';
/**
* Sets the comment's values in the given postElement.
*/
function setCommentValues(postElement, id, text, author) {
var comment = postElement.getElementsByClassName('comment-' + id)[0];
comment.getElementsByClassName('comment')[0].innerText = text;
comment.getElementsByClassName('fp-username')[0].innerText = author;
}
/**
* Deletes the comment of the given ID in the given postElement.
*/
function deleteComment(postElement, id) {
var comment = postElement.getElementsByClassName('comment-' + id)[0];
comment.parentElement.removeChild(comment);
}
/**
* Starts listening for new posts and populates posts lists.
*/
function startDatabaseQueries() {
// [START my_top_posts_query]
var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().ref('user-posts/' +
myUserId).orderByChild('starCount');
// [END my_top_posts_query]
// [START recent_posts_query]
var recentPostsRef = firebase.database().ref('posts').limitToLast(100);
// [END recent_posts_query]
var userPostsRef = firebase.database().ref('user-posts/' + myUserId);
/**
* Writes the user's data to the database.
*/
// [START basic_write]
function writeUserData(userId, name, email, imageUrl) {
firebase.database().ref('users/' + userId).set({
username: name,
email: email,
profile_picture : imageUrl
});
}
// [END basic_write]
/**
* Cleanups the UI and removes all Firebase listeners.
*/
function cleanupUi() {
// Remove all previously displayed posts.
topUserPostsSection.getElementsByClassName('posts-container')[0].innerHTML = '';
recentPostsSection.getElementsByClassName('posts-container')[0].innerHTML = '';
userPostsSection.getElementsByClassName('posts-container')[0].innerHTML = '';
/**
* The ID of the currently signed-in User. We keep track of this to detect Auth
state change events that are just
* programmatic token refresh but not a User status change.
*/
var currentUID;
/**
* Triggers every time there is a change in the Firebase auth state (i.e. user
signed-in or user signed out).
*/
function onAuthStateChanged(user) {
// We ignore token refresh events.
if (user && currentUID === user.uid) {
return;
}
cleanupUi();
if (user) {
currentUID = user.uid;
splashPage.style.display = 'none';
writeUserData(user.uid, user.displayName, user.email, user.photoURL);
startDatabaseQueries();
} else {
// Set currentUID to null.
currentUID = null;
// Display the splash page where you can sign-in.
splashPage.style.display = '';
}
}
/**
* Creates a new post for the current user.
*/
function newPostForCurrentUser(title, text) {
// [START single_value_read]
var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' +
userId).once('value').then(function(snapshot) {
var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
// [START_EXCLUDE]
return writeNewPost(firebase.auth().currentUser.uid, username,
firebase.auth().currentUser.photoURL,
title, text);
// [END_EXCLUDE]
});
// [END single_value_read]
}
/**
* Displays the given section element and changes styling of the given button.
*/
function showSection(sectionElement, buttonElement) {
recentPostsSection.style.display = 'none';
userPostsSection.style.display = 'none';
topUserPostsSection.style.display = 'none';
addPost.style.display = 'none';
recentMenuButton.classList.remove('is-active');
myPostsMenuButton.classList.remove('is-active');
myTopPostsMenuButton.classList.remove('is-active');
if (sectionElement) {
sectionElement.style.display = 'block';
}
if (buttonElement) {
buttonElement.classList.add('is-active');
}
}
// Bindings on load.
window.addEventListener('load', function() {
// Bind Sign in button.
signInButton.addEventListener('click', function() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider);
});