Skip to content

Instantly share code, notes, and snippets.

@semlak
Created November 23, 2017 20:36
Show Gist options
  • Select an option

  • Save semlak/1233c57e47da03de1fb3fca8e081b14c to your computer and use it in GitHub Desktop.

Select an option

Save semlak/1233c57e47da03de1fb3fca8e081b14c to your computer and use it in GitHub Desktop.
FreeCodeCamp Zipline: Wikipedia viewer
<div class="container">
<div class="row verticle-center-row">
<div class="col-md-12">
<div id='app-container'>
<div id='intro'>
<h2>FreeCodeCamp Zipline</h2>
<p>Wikipedia search and view</p>
</div>
<div id="app-search">
<div id='search-bar'>
<div class='animated-search-bar' id='left-circle'>
<div id='left-cover-circle' class='click-to-expand'></div>
<div id='left-cover-circle-larger-invisible' class='click-to-expand'></div>
</div>
<div class='animated-search-bar' id='bar-between-circle-halfs'>
<input type="text" name="searchQuery" id='searchQueryField' class='show-when-expanded' hidden autocomplete="off">
<div class="glyphicon glyphicon-remove show-when-expanded" id='search-box-glyph-remove' hidden></div>
</div>
<div class='animated-search-bar' id='right-circle'>
<div id='right-cover-circle' class='click-to-expand'></div>
<div id='magnifier-handle' class='show-when-collapsed click-to-expand'></div>
<div id='random-article-image-div' class='show-when-collapsed'>
<img src='https://pomma89.altervista.org/troschuetz/logo.256.png' id='random-article-image'>
</div>
</div>
<!--<div id='inner-cover-circle1'></div> -->
</div>
<p id='instruction-message'>Click magnifier icon to search, or click the dice icon for a random article</p>
<div id='search-results-container'>
</div>
</div>
<!--end of .col-md-4 div -->
</div>
<!-- end of .row div -->
</div>
<!-- end of .container div -->
//right now, the app runs one query for the initial search, and then runs a query for each of those items. It would be nice to combine these with the generater feature
//Right now, it displays the article introduction. I would like to change this so I grab the whole article, extract just the introduction, and then have the ability to expand the introduction to the full article. However, I currently retrieve text with no links, so the full articles might be a bit odd.
//It would be nice to refactor the searching, parsing, and adding to results.
var baseURL = 'https://en.wikipedia.org';
var articleURL = '/wiki/'
var apiURL = 'w/api.php';
var randomArticleAPICall = 'https://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exintro&format=json&callback=?';
var searchBarStatus = 'collapsed' ;
//can be 'expanded' or 'collapsed'. Starts 'collapsed'
var currentAnimation = 'none'
//can be 'none', 'expanding', 'collapsing.
var truncateString = function(str, num) {
// Clear out that junk in your trunk
str = str.trim();
//console.log("string is " + str);
if (str.length > num) {
if (str.length <= 3) {
str = str.substring(0, num) + "...";
}
else {
//console.log("hello. num is " + num);
str = str.substring(0, num - 3) + "...";
}
}
return str;
};
var capitalizeFirstLetter = function (string) {
//http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
if (string.indexOf(' ') < 0) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
else {
return string.split(' ').map(function(element) {
return element.charAt(0).toUpperCase() + element.slice(1)
}).join(' ');
}
};
var animateSearchBar = function(t, action) {
var time = t || .2;
//action is either 'expand' or 'collapse' as a string
var elements = document.getElementsByClassName('animated-search-bar');
//console.log("elements :", elements);
for (var i = 0; i < elements.length ; i++ ) {
var element = elements[i];
$("#" + element.id).css('animation', action + "-" + element.id + " " + time + "s linear 1");
}``
$(".animated-search-bar").css('animation-fill-mode', 'forwards');
$(".animated-search-bar").css('animation-play-state', 'running');
}
var collapseSearchBar = function(t) {
//t can be input in seconds. Default is one second.
var time = t || .2;
if (searchBarStatus !== 'expanded') {
alert("SearchBarStatus not collapsed. Shouldn't have received this alert");
}
else {
currentAnimation = 'collapsing';
animateSearchBar(time, 'collapse');
}
};
var expandSearchBar = function(t) {
//t can be input in seconds. Default is one second.
var time = t || .2;
if (searchBarStatus !== 'collapsed') {
alert("SearchBarStatus not collapsed. Shouldn't have received this alert");
}
else {
currentAnimation = 'expanding';
animateSearchBar(time, 'expand');
}
};
var animationListener = function(e) {
//console.log("hey", e.type);
switch(e.type) {
case "animationstart":
//console.log("Started: elapsed time is " + e.elapsedTime, "currentAnimation: ", currentAnimation);
if (currentAnimation === 'collapsing') {
$('.show-when-expanded').hide();
}
else {
$('.show-when-collapsed').hide();
}
break;
case "animationend":
//console.log("Ended: elapsed time is " + e.elapsedTime);
if (currentAnimation === 'collapsing') {
searchBarStatus = 'collapsed' ;
$('.show-when-collapsed').show();
}
else {
searchBarStatus = 'expanded' ;
$('.show-when-expanded').show();
}
currentAnimation = 'none';
$(".animated-search-bar").css('animation-play-state', 'paused');
break;
}
};
var setupListeners = function() {
var e = $("#left-circle")[0];
//console.log("element:", e);
e.addEventListener("animationstart", animationListener, false);
e.addEventListener("animationend", animationListener, false);
};
var showProgressMessage = function(searchQuery) {
var articleDiv = $("<div class='article-result message' id='in-progress'></div>");
if (searchQuery) {
var itemHTML =
"<p>Search in progres for query '" + searchQuery + "'.</p>";
}
else {
var itemHTML =
"<p>Loading random article</p>";
}
articleDiv.html(itemHTML);
articleDiv.hidden = 'true';
$('#search-results-container').append(articleDiv);
$('#in-progress').show('fold', 500);
}
var showNoResultsMessage = function(searchQuery) {
var articleDiv = $("<div class='article-result message' id='no-results'></div>");
var itemHTML =
"<p>No results were found for the query '" + searchQuery + "'.</p>";
articleDiv.html(itemHTML);
articleDiv.hidden = 'true';
$('#search-results-container').append(articleDiv);
$('#no-results').show('fold', 5000);
};
var addArticleToResultsold = function(data) {
var item = {
'url' : baseURL + articleURL + data.title,
'snippet' : data.snippet,
'title' : data.title
};
var articleDiv = $("<div class='article-result' id='" + item.title+ "'></div>");
var itemHTML =
"<a href='" + item.url + "' target='_blank'><h3><b>" + item.title + "</b></h3><p>" + item.snippet + "</p></a>";
articleDiv.html(itemHTML);
//appendTableItemToTable(tableItem);
$('#search-results-container').append(articleDiv);
};
var addArticleToResults = function(data, url) {
var item = {
'url' : baseURL + articleURL + data.title,
'snippet' : data.snippet,
'title' : data.title,
'extract' : ''
};
var queryForIntro = baseURL + '/' + apiURL + '?' +
createQueryString({'action' :'query',
'prop' :'extracts',
'format':'json',
'titles' :item.title
}) +
'&exintro&callback=?';
//console.log(queryForIntro);
$.getJSON(queryForIntro, function(data) {
if (data.query ) {
//console.log(data.query.pages);
for (var page in data.query.pages) {
// data.query.search.forEach(function(element) {
var element = data.query.pages[page];
if (item.extract !== '') {
alert('was not expacting to have mutltiple objects here');
}
else {
//console.log(element.extract);
item.extract = element.extract;
var articleDiv = $("<div class='article-result' id='" + item.title+ "'></div>");
var itemHTML =
"<a href='" + item.url + "' target='_blank'><h3><b>" + item.title + "</b></h3></a>" + item.extract;
articleDiv.html(itemHTML);
$('#search-results-container').append(articleDiv);
}
}
//});
//should handle greater than 10 hits
}
else {
showNoResultsMessage(searchQuery);
}
});
};
var createQueryString = function (options) {
var query = [];
for (var i in options) {
if (options.hasOwnProperty(i)) {
query.push(encodeURIComponent(i) + '=' + encodeURIComponent(options[i]));
}
}
return query.join('&');
};
var runQuery = function(searchQuery) {
var initialURL = baseURL + "/" + apiURL ;
//var action = 'opensearch';
var action = 'query'
var list = 'search'
//var searchQuery = 'warrior princess';
//searchQuery = 'Xena';
var searchOptions = {
'action' : action,
'list' : list,
'srsearch' : 'intitle:' + searchQuery,
'format' : 'json'
};
var queryString = createQueryString(searchOptions);
var fullQueryString = initialURL + '?' + queryString + '&callback=?';
//console.log(fullQueryString);
$.getJSON(fullQueryString, function(data) {
if (data.query.search.length > 0 ) {
$('#in-progress').slideUp(300, function() {this.remove();});
data.query.search.forEach(function(element) {
addArticleToResults(element);
});
//should handle greater than 10 hits
}
else {
showNoResultsMessage(searchQuery);
}
});
};
var runQueryOld = function(searchQuery) {
var initialURL = baseURL + "/" + apiURL ;
//var action = 'opensearch';
var action = 'query'
var list = 'search'
//var searchQuery = 'warrior princess';
//searchQuery = 'Xena';
var searchOptions = {
'action' : action,
'list' : list,
'srsearch' : searchQuery,
'format' : 'json'
};
var queryString = createQueryString(searchOptions);
var fullQueryString = initialURL + '?' + queryString + '&callback=?';
$.getJSON( fullQueryString, function(data) {
if (data.query.search.length > 0 ) {
data.query.search.forEach(function(element) {
addArticleToResults(element);
});
//should handle greater than 10 hits
}
else {
showNoResultsMessage(searchQuery);
}
});
};
var loadRandomArticle = function() {
//alert("Loading random article");
$.getJSON(randomArticleAPICall, function(data) {
if (data.query ) {
//console.log(data.query.pages);
var numItems = 0;
for (var page in data.query.pages) {
numItems++;
if (numItems > 1) {
alert('was not expacting to have mutltiple objects here');
}
else {
$('#in-progress').slideUp(300, function() {this.remove();});
// data.query.search.forEach(function(element) {
var element = data.query.pages[page];
var item = {
'url' : baseURL + articleURL + element.title,
'title' : element.title,
'extract' : element.extract
};
var articleDiv = $("<div class='article-result' id='" + item.title+ "'></div>");
var itemHTML =
"<a href='" + item.url + "' target='_blank'><h3><b>" + item.title + "</b></h3></a>" + item.extract;
articleDiv.html(itemHTML);
$('#search-results-container').append(articleDiv);
}
}
}
});
};
var prepForQuery = function() {
$('#search-results-container').empty(300, function() {this.remove();});
$('#intro').slideUp(300, function() {this.remove();});
$('#instruction-message').slideUp(300, function() {this.remove();});
};
$(document).ready(function(){
setupListeners();
$('.show-when-expanded').hide();
$('#search-box-glyph-remove').on('click', function() {
$("#searchQueryField").val('');
collapseSearchBar();
});
$('.click-to-expand').on('click', function() {
//alert('hey');
if (searchBarStatus === 'collapsed') {
$('#instruction-message').remove();
expandSearchBar();
}
});
$('#random-article-image').on('click', function() {
prepForQuery();
showProgressMessage();
loadRandomArticle();
});
$('#searchQueryField').keyup(function(e){
if (!e) e = window.event;
var keyCode = e.keyCode || e.which;
//console.log(keyCode, e.currentTarget.value);
if (keyCode === 13){
//console.log("Enter pressed");
prepForQuery();
showProgressMessage(e.currentTarget.value);
runQuery(e.currentTarget.value);
}
else {
//possible use to provide autocomplete suggestions
//console.log("hey");
}
});
//runQuery('Xena');
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
/* making a css magnifying glass:
https://www.youtube.com/watch?v=czAp_gwh8P0
*/
/*
* {
box-sizing: border-box;
}
*/
body {
background: #003366; /*very dark blue */
}
#app-container {
margin: 20px 0 20px 0;
}
#app-search {
}
#instruction-message {
color: #fff;
margin: auto;
text-align: center;
}
.article-result {
background: #fff;
border: 2px sollid #000;
font-color: #000;
padding: 10px;
margin-bottom: 20px;
margin-top: 20px;
box-shadow: 6px 6px 10px ;
}
a:link, a:hover, a:active, a:visited {
color: #000;
text-decoration: underline;
}
#start-button {
/*
position: relative;
top: 0px;
left: 800px;
*/
z-index: 70;
}
#intro {
/*margin-top: 40px;*/
color: #000;
background: #fff;
border: 2px solid #000;
width: 400px;
padding-bottom: 20px;
margin: auto;
margin-top: 10px;
margin-bottom: -10px;
text-align: center;
}
.message {
width: 400px;
margin: auto;
text-align: center;
}
#random-article-image-div {
position: relative;
top: -70px;
left: 100px;
}
#random-article-image {
height: 50px;
}
#search-bar {
margin: auto;
margin-top: 40px;
margin-bottom: -60px;
}
#left-circle {
height: 50px;
width: 50px;
border-radius: 50%;
border : 4px solid #D2691E; /*chocolate color */
position: relative;
top: 0px;
left: 0px;
margin: auto;
}
#bar-between-circle-halfs {
height: 50px;
width: 0px;
border-top : 4px solid #D2691E; /*chocolate color */
border-bottom : 4px solid #D2691E; /*chocolate color */
position: relative;
top: -50px;
left: 0px;
z-index: 20;
opacity: 1;
background: #003366; /*very dark blue */
margin: auto;
}
#right-circle {
height: 50px;
width: 50px;
border-radius: 50%;
border : 4px solid #D2691E; /*chocolate color */
position: relative;
top: -100px;
left: 0px;
z-index: -10px;
margin: auto;
}
#magnifier-handle {
height: 30px;
width: 12px;
border-radius: 0 0 10px 10px;
border : 4px solid #D2691E; /*chocolate color */
position: relative;
top: -10px;
left: 26px;
z-index: 20px;
margin: auto;
transform: rotate(-45deg);
}
#left-cover-circle {
color: #000;
width: 42px;
height: 42px;
border-radius: 50%;
position: relative;
top: 0px;
left: 0px;
z-index: 10;
opacity: 1;
background: #003366; /*very dark blue */
margin: auto;
}
#left-cover-circle-larger-invisible {
color: #000;
width: 52px;
height: 52px;
border-radius: 50%;
position: relative;
top: -47px;
left: -5px;
z-index: 30;
opacity: 0;
background: #000; /*very dark blue */
margin: auto;
}
#right-cover-circle {
color: #000;
width: 42px;
height: 42px;
border-radius: 50%;
position: relative;
top: 0px;
left: 0px;
z-index: 10;
opacity: 1;
background: #003366; /*very dark blue */
margin: auto;
}
#searchQueryField {
position: relative;
top: 10px;
left: -5px;
width: 290px;
z-index: 60;
background: #003366; /*very dark blue */
color: #fff;
border: none;
}
#searchQueryField:focus {
outline: 0;
}
#search-box-glyph-remove {
position: relative;
left: 290px;
top: -8px;
color: #D2691E;
font-size: 15px;
/*margin-top: -46px;
margin-left: 300px; */
}
@keyframes expand-left-circle {
0% { left: -0px; }
100% { left: -150px; }
}
@keyframes expand-right-circle {
0% { left: 0px; }
100% { left: 150px; }
}
@keyframes expand-bar-between-circle-halfs {
0% { width: 0px; }
100% { width: 300px; }
}
@keyframes collapse-left-circle {
0% { left: -150px; }
100% { left: 0px; }
}
@keyframes collapse-right-circle {
0% { left: 150px; }
100% { left: 0px; }
}
@keyframes collapse-bar-between-circle-halfs {
0% { width: 300px; }
100% { width: 0px; }
}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment