528491 / Project-1

0 stars 1 forks source link

North Hollywood Church

Overview

Web-site for a North-Hollywood based Church with Bootstrap CSS for styling; makes use of the Facebook Graph, Google Maps Directions, and YouTube APIs. Also features Firebase authentication with both federated resource providers and direct sign in with email and password.

Technologies Used

Code Explanation

Styling

Styling was achieved via the Bootstrap CSS framework, with custom CSS added as needed. JQuery was also utilized, primarily for ease of readability with regards to the JavaScript code.

Functionality

In addition, the following services were utilized, accessed via the JavaScript API.

Facebook Graph API

In order to use Facebook Graph API, we need to use developers.facebook.com to create App ID and App Secret for our application. We use App ID and App Secret to get access token for our application. For each query on Facebook Graph API we need to add access token in order to get authenticated.

Some fields required additional review by Facebook in order to be approved for usage in live applications. Right now, we cannot submit review request since Facebook is reviewing its policies. Future political climates might allow for the integration of these features as planned.

Google Maps Directions API

Display travel directions on map and detail turn by turn to user. We added AutoComplete address to the input box. Map will look for addresses as user typing in. User can pick an address from the suggested list.

//Global Variables
var placeSearch, autocomplete, marker;

function init () {
      var directionsDisplay = new google.maps.DirectionsRenderer;
      var directionsService = new google.maps.DirectionsService;
      var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 14,
        center: {lat: 34.251268, lng: -118.441183}
      });
      directionsDisplay.setMap(map);

      //Details Button click
      document.getElementById('detailsBtn').addEventListener('click', function () {
          //Display detail panel
          directionsDisplay.setPanel(document.getElementById('bottom-panel'));
          var control = document.getElementById('floating-panel');
          control.style.display = 'block';
          map.controls[google.maps.ControlPosition.TOP_CENTER].push(control);
      });

      //Event Listener to change on start location and travel mode
      var onChangeHandler = function() {
          calculateAndDisplayRoute(directionsService, directionsDisplay);
      };
      //Invoke function calculateAndDisplayRoute on change of location and travel mode
      document.getElementById('start').addEventListener('change', onChangeHandler);
      document.getElementById('mode').addEventListener('change', onChangeHandler);

      // Create the autocomplete object, restricting the search to geographical
      // location types.
      autocomplete = new google.maps.places.Autocomplete(
              /** @type {!HTMLInputElement} */(document.getElementById('start')),
          { types: ['geocode'] });

      //Added Marker code
      marker = new google.maps.Marker({
            map: map,
            draggable: false,
            animation: google.maps.Animation.DROP,
            position: { lat: 34.251268, lng: -118.441183 },
            title: 'Vietnamese Evangelical Church (Hội Thánh Tin Lành Việt Nam) North Hollywood'
          });
          marker.addListener('click', toggleBounce);

        //Marker bounces on mouse click
        function toggleBounce() {
          if (marker.getAnimation() !== null) {
            marker.setAnimation(null);
          } 
          else {
            marker.setAnimation(google.maps.Animation.BOUNCE);
          }
        }//End of marker code
}//end of init function

// Bias the autocomplete object to the user's geographical location,
// as supplied by the browser's 'navigator.geolocation' object.
function geolocate() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function (position) {
      var geolocation = {
        lat: position.coords.latitude,
        lng: position.coords.longitude
      };
      var circle = new google.maps.Circle({
        center: geolocation,
        radius: position.coords.accuracy
      });
      autocomplete.setBounds(circle.getBounds());
    });
  }
}//end of geolocate()

//calculate and display route base on travel mode
function calculateAndDisplayRoute(directionsService, directionsDisplay) {
    //Travel Mode value
    var selectedMode = document.getElementById('mode').value;
    //Start location value input
    var start = document.getElementById('start').value;
    //Assigned end location
    var end = "9936 Beachy Ave. Arleta, CA 91331";

    directionsService.route({
      origin: start, 
      destination: end,
      // Note that Javascript allows us to access the constant
      // using square brackets and a string value as its
      // "property."
      travelMode: google.maps.TravelMode[selectedMode]
    }, function(response, status) {
      if (status == 'OK') {
        directionsDisplay.setDirections(response);
      } 
      else {
        return;
      }
    });
  }//end of function calculateAndDisplayRoute

YouTube API

The displaying of the client’s YouTube videos was accomplished via two HTTP GET requests. The first request retrieved the YouTube ID of the client’s channel uploads, and the second request used this ID to display thumbnails of the channel’s videos and an iframe element to the page. The following is an example of these two GET requests, with each request being part of a function. Note that the second GET request is inside the first, and that an additional function is needed to attach click events to the displayed thumbnails.

var channelName = "ChurchNorthHollywood";

var channelInfo = {
   part: 'contentDetails',
   forUsername: channelName,
   key: 'AIzaSyCqxm1KaFeRuiGu1vl6YcaDnmg7mU0mU_4'
}

$(document).ready(function() {

   function getInfo() {

       // ==== first "get" request to get ID of the uploads of the Church's YouTube channel. ====
       $.get(
           "https://www.googleapis.com/youtube/v3/channels", channelInfo, function(data) {
               $.each(data.items, function(i, item) {                              // index is "i"; items[i] === item
                   pid = item.contentDetails.relatedPlaylists.uploads;             // the "uploads" playlist ID

                   // the second "get" request to display the thumbnails.
                   getVids(pid);
               })
           }
       );
   }

   getInfo();

   // variable connected to the number of results received from the second "get" request
   var resultNumber = 10;                                                         

   // ==== the second "get" request to display the thumbnails. ====
   // ==== takes the playlist ID
   function getVids(pid) {

       $("#videos").empty();                                                       // Prevents duplicate videos from being displayed.
       $.get(
           "https://www.googleapis.com/youtube/v3/playlistItems", {
               part: 'snippet',
               maxResults: resultNumber,
               playlistId: pid,
               key: 'AIzaSyCqxm1KaFeRuiGu1vl6YcaDnmg7mU0mU_4',

           }, function(data) {
               var output;
               $.each(data.items, function(i, item) {                              // index is "i"; items[i] === item

                   videoTitle = item.snippet.title;                                // title of the video
                   videoThumb = item.snippet.thumbnails.default.url;               // the url for the videos' thumbnails

                   // ==== "making" the thumbnails ====
                   thumbnailDisplay = $("<img></img>")                       
                   $(thumbnailDisplay).attr("src", videoThumb);
                   var thumbnailClickable = $("<a></a>");                          // makes the thumbnails obviously clickable to the user
                   $(thumbnailClickable).attr("href", "#");                        // this href link won't redirect anywhere
                   $(thumbnailClickable).append(thumbnailDisplay);                 // puts the thumbnail display inside thumbnailClickable

                   $("#videos").append(videoTitle);                                // displays the video title

                   // === Displaying thumbnails to page ===
                   output = $("<div class = 'thumbnail'></div>");                  // this div will hold the thumbnail
                   var thumbnailId = "thumbnail-" + i;                             // the id that we will attach to the thumbnail div
                   $(output).attr("id", thumbnailId);                              // attaches the above id to the thumbnail div
                   $(output).html(thumbnailClickable);                             // putting the thumbnail we created inside the "output" div                               
                   $("#videos").append(output);                                    // displays the video thumbnails inside the #videos div

                   // ==== spacing to separate videos ====
                   spacing = $("<div class = 'space'></div>");
                   $("#videos").append(spacing); 

                   // ==== Function to display the clicked video to the webpage. ====
                   getVidInfo(thumbnailId, item);                                 

                   // ==== variable to keep track of the number of thumbnails displayed. ====
                   var numThumbs = $(".thumbnail").length;

                   // ==== if the number of displayed thumbs equals the max number of videos on the channel ====
                   if (numThumbs === data.pageInfo.totalResults) {
                       stopButton();
                   }
               })

               // ==== Displaying an initial video when page loads ====
               var firstVidId = data.items[0].snippet.resourceId.videoId;

               var videoLink = $("<iframe class = 'display'></iframe>");
               $(videoLink).attr("src", "https://www.youtube.com/embed/" + firstVidId);

               $("#vid-display").append(videoLink);                                            // displays the video

           }
       );
   }

   function getVidInfo(thumbnailId, item) {
       $("#" + thumbnailId).on("click", function(event) {

           event.preventDefault();

           // prevents duplicates from being displayed
           $("#vid-display").empty();

           var videoId = item.snippet.resourceId.videoId;                                  // gets the video id of the clicked thumbnail's video

           var videoLink = $("<iframe class = 'display'></iframe>");
           $(videoLink).attr("src", "https://www.youtube.com/embed/" + videoId);

           $("#vid-display").append(videoLink);                                            // displays the video

       })
   }

   // when pressing the "load more videos" button, load more videos.
   $("#vid-load").on("click", function(event) {
       event.preventDefault();
       resultNumber = resultNumber + 10;
       $("#load-message").html("10 more videos loaded.");
       getInfo();
   })

   // function that runs when all the channel's videos are displayed
   function stopButton() {
       $("#vid-load").off("click");
       $("#load-message").html("All videos loaded.");
   }

});

Authentication

Authentication was implemented using the firebase auth api, which allows users to authenticate via one of several methods:

Lessons Learned

Future Plans