/*
* @file Manages all library initialization, jQuery callbacks, query entry
* callbacks, server querying, and results diplay for `index.html`.
*/
var advancedSearchDiv = $("div#advanced-search");
var advancedSearchButton = $("button#advanced-search");
FINISH_TYPING_INTERVAL = 650;
var searchBar = $("form#search-bar input[type='text']")[0];
var resultsDiv = $("div#results")[0];
var typingTimer, lastValue;
/*
* Set all page callbacks.
*/
(function setHomePageCallbabacks(){
// Enable infinite scrolling down the results page.
$(window).scroll(function(){
if($(window).scrollTop() + $(window).height() == $(document).height() &&
resultsDiv.querySelectorAll(".result").length > 0)
loadMoreResults();
});
// Toggle the advanced-search form's visibility.
advancedSearchButton.click(function(){
var searchField = $("div#search-field");
if(!advancedSearchDiv.hasClass("visible")){
searchField.addClass("partly-visible");
advancedSearchDiv.fadeIn(500).addClass("visible");
advancedSearchButton.addClass("clicked");
}
else {
advancedSearchDiv.fadeOut(300).removeClass("visible");
advancedSearchButton.removeClass("clicked");
if($("div#results .result").length == 0)
searchField.removeClass("partly-visible");
}
});
// Enable capturing the `enter` key.
$("form#search-bar").submit(function(event){
event.preventDefault();
return false;
});
searchBar.onkeyup = typingTimer;
}());
//Obtained by parsing python file with pygments
var codeExample = '
1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40 | """\nModule to contain all the project's Flask server plumbing.\n"""\n\nfrom flask import Flask\nfrom flask import render_template, session\n\nfrom bitshift import assets\n# from bitshift.database import Database\n# from bitshift.query import parse_query\n\napp = Flask(__name__)\napp.config.from_object("bitshift.config")\n\napp_env = app.jinja_env\napp_env.line_statement_prefix = "="\napp_env.globals.update(assets=assets)\n\n# database = Database()\n\n@app.route("/")\ndef index():\n return render_template("index.html")\n\n@app.route("/search/<query>")\ndef search(query):\n # tree = parse_query(query)\n # database.search(tree)\n pass\n\n@app.route("/about")\ndef about():\n return render_template("about.html")\n\n@app.route("/developers")\ndef developers():\n return render_template("developers.html")\n\nif __name__ == "__main__":\n app.run(debug=True)\n \n |
'
searchBar.onkeyup = typingTimer;
var testCodelet = {
'url': 'https://github.com/earwig/bitshift/blob/develop/app.py',
'filename': 'app.py',
'language': 'python',
'date_created': 'May 10, 2014',
'date_modified': '2 days ago',
'origin': ['GitHub', 'https://github.com', ''],
'authors': ['sevko', 'earwig'],
'html_code': codeExample
};
// Enable infinite scrolling down the results page.
$(window).scroll(function() {
var searchField = $("div#search-field");
if($(window).scrollTop() + $(window).height() == $(document).height() && searchField.hasClass('partly-visible')){
loadMoreResults();
}
});
/*
* Clear the existing timer and set a new one the the user types text into the
* search bar.
*/
function typingTimer(event){
clearTimeout(typingTimer);
var enterKeyCode = 13;
if(event.keyCode != enterKeyCode){
if(lastValue != searchBar.value)
typingTimer = setTimeout(finishedTyping, FINISH_TYPING_INTERVAL);
}
else {
event.preventDefault();
finishedTyping();
return false;
}
};
/*
* Callback which queries the server whenver the user stops typing.
*
* Whenever the user doesn't type for a `FINISH_TYPING_INTERVAL` after having
* entered new text in the search bar, send the current query request to the
* server.
*/
function finishedTyping(){
lastValue = searchBar.value;
var searchField = $("div#search-field");
clearResults();
if(searchBar.value){
searchField.addClass("partly-visible");
populateResults();
}
else {
searchField.removeClass("partly-visible");
$("div#advanced-search").fadeOut(50);
advancedSearchButton.removeClass("clicked");
}
}
/*
* Removes any child elements of `div#results`.
*/
function clearResults(){
while(resultsDiv.firstChild)
resultsDiv.removeChild(resultsDiv.firstChild);
}
/*
* Query the server with the current search string, and populate `div#results`
* with its response.
*/
function populateResults(){
var results = queryServer();
for(var result = 0; result < results.length; result++){
var newDiv = results[result];
resultsDiv.appendChild(newDiv);
setTimeout(
(function(divReference){
return function(){
divReference.classList.add("cascade");
};
}(newDiv)), result * 20);
}
}
/*
* Create a result element based upon a codelet instance.
*
* @return {Element} The result element.
*/
function createResult(codelet) {
//Level 1
var newDiv = document.createElement("div"),
table = document.createElement("table"),
row = document.createElement("tr");
//Level 2
var displayInfo = document.createElement("div"),
codeElt = document.createElement("td"),
hiddenInfoContainer = document.createElement("td"),
hiddenInfo = document.createElement("div");
//Level 3
var title = document.createElement("span"),
site = document.createElement("span"),
dateModified = document.createElement("div"),
language = document.createElement("span"),
dateCreated = document.createElement("div"),
authors = document.createElement("div");
//Classes and ID's
newDiv.classList.add('result');
displayInfo.id = 'display-info';
codeElt.id = 'code';
hiddenInfo.id = 'hidden-info';
title.id = 'title';
site.id = 'site';
dateModified.id = 'date-modified';
language.id = 'language';
dateCreated.id = 'date-created';
authors.id = 'authors';
//Add the bulk of the html
title.innerHTML = 'File '
+ codelet.filename + '';
site.innerHTML = 'on ' + codelet.origin[0] +'';
language.innerHTML = codelet.language;
dateModified.innerHTML = 'Last modified: ' + codelet.date_modified + '';
// Needs to be changed from int to string on the server
dateCreated.innerHTML = 'Created: ' + codelet.date_created + '';
var authorsHtml = 'Authors: ';
codelet.authors.forEach(function(a, i) {
if (i == codelet.authors.length - 1)
authorsHtml += '' + a + ' ';
else
authorsHtml += '' + a + ' , ';
});
authors.innerHTML = authorsHtml;
// Needs to be processed on the server
codeElt.innerHTML = '' + codelet.html_code + '
';
//Event binding
$(newDiv).hover(function(e) {
$(row).addClass('display-all');
});
$(newDiv).on('transitionend', function(e) {
$(newDiv).one('mouseleave', function(e) {
$(row).removeClass('display-all');
});
});
//Finish and append elements to parent elements
hiddenInfo.appendChild(dateCreated);
hiddenInfo.appendChild(dateModified);
hiddenInfo.appendChild(authors);
hiddenInfoContainer.appendChild(hiddenInfo);
row.appendChild(codeElt);
row.appendChild(hiddenInfoContainer);
table.appendChild(row);
displayInfo.appendChild(title);
displayInfo.appendChild(site);
displayInfo.appendChild(language);
newDiv.appendChild(displayInfo);
newDiv.appendChild(table);
return newDiv;
}
/*
* AJAX the current query string to the server, and return its response.
*
* @return {Array} The server's response in the form of `div.result` DOM
* elements, to fill `div#results`.
*/
function queryServer(){
var resultDivs = []
for(var result = 0; result < 20; result++){
var newDiv = createResult(testCodelet);
resultDivs.push(newDiv);
}
return resultDivs;
}
/*
* Adds more results to `div#results`.
*/
function loadMoreResults(){
results = queryServer();
for(var result = 0; result < results.length; result++){
var newDiv = results[result];
resultsDiv.appendChild(newDiv);
setTimeout(
(function(divReference){
return function(){
divReference.classList.add("cascade");
};
}(newDiv)),
result * 20);
}
}