A semantic search engine for source code https://bitshift.benkurtovic.com/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

236 lines
6.5 KiB

  1. /*
  2. * @file Manages all library initialization, jQuery callbacks, query entry
  3. * callbacks, server querying, and results diplay for `index.html`.
  4. */
  5. var advancedSearchDiv = $("div#advanced-search");
  6. var advancedSearchButton = $("button#advanced-search");
  7. advancedSearchButton.click(function(){
  8. var searchField = $("div#search-field");
  9. if(!advancedSearchDiv.hasClass("visible")){
  10. searchField.addClass("partly-visible");
  11. advancedSearchDiv.fadeIn(500).addClass("visible");
  12. advancedSearchButton.addClass("clicked");
  13. }
  14. else {
  15. advancedSearchDiv.fadeOut(300).removeClass("visible");
  16. advancedSearchButton.removeClass("clicked");
  17. if($("div#results .result").length == 0)
  18. searchField.removeClass("partly-visible");
  19. }
  20. });
  21. $("#date-last-modified").datepicker();
  22. $("#date-created").datepicker();
  23. var languages = new Bloodhound({
  24. datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"),
  25. queryTokenizer: Bloodhound.tokenizers.whitespace,
  26. local: $.map(TYPEAHEAD_LANGUAGES, function(state){
  27. return {value : state};
  28. })
  29. });
  30. languages.initialize();
  31. $("#languages.typeahead").typeahead({
  32. hint: true,
  33. highlight: true,
  34. minLength: 1
  35. },
  36. {
  37. name: "languages",
  38. displayKey: "value",
  39. source: languages.ttAdapter()
  40. });
  41. FINISH_TYPING_INTERVAL = 650;
  42. searchBar = $("form#search-bar input[type='text']")[0];
  43. resultsDiv = $("div#results")[0];
  44. var typingTimer, lastValue;
  45. searchBar.onkeyup = typingTimer;
  46. // Enable infinite scrolling down the results page.
  47. $(window).scroll(function() {
  48. if($(window).scrollTop() + $(window).height() == $(document).height()){
  49. loadMoreResults();
  50. }
  51. });
  52. // Enable capturing the `enter` key.
  53. $("form#search-bar").submit(function(event){
  54. event.preventDefault();
  55. return false;
  56. });
  57. /*
  58. * Clear the existing timer and set a new one the the user types text into the
  59. * search bar.
  60. */
  61. function typingTimer(event){
  62. clearTimeout(typingTimer);
  63. var enterKeyCode = 13;
  64. if(event.keyCode != enterKeyCode){
  65. if(lastValue != searchBar.value)
  66. typingTimer = setTimeout(finishedTyping, FINISH_TYPING_INTERVAL);
  67. }
  68. else {
  69. event.preventDefault();
  70. finishedTyping();
  71. return false;
  72. }
  73. };
  74. /*
  75. * Callback which queries the server whenver the user stops typing.
  76. *
  77. * Whenever the user doesn't type for a `FINISH_TYPING_INTERVAL` after having
  78. * entered new text in the search bar, send the current query request to the
  79. * server.
  80. */
  81. function finishedTyping(){
  82. lastValue = searchBar.value;
  83. var searchField = $("div#search-field");
  84. clearResults();
  85. if(searchBar.value){
  86. searchField.addClass("partly-visible");
  87. populateResults();
  88. }
  89. else {
  90. searchField.removeClass("partly-visible");
  91. $("div#advanced-search").fadeOut(50);
  92. advancedSearchButton.removeClass("clicked");
  93. }
  94. }
  95. /*
  96. * Removes any child elements of `div#results`.
  97. */
  98. function clearResults(){
  99. while(resultsDiv.firstChild)
  100. resultsDiv.removeChild(resultsDiv.firstChild);
  101. }
  102. /*
  103. * Query the server with the current search string, and populate `div#results`
  104. * with its response.
  105. */
  106. function populateResults(){
  107. var results = queryServer();
  108. for(var result = 0; result < results.length; result++){
  109. var newDiv = results[result];
  110. resultsDiv.appendChild(newDiv);
  111. setTimeout(
  112. (function(divReference){
  113. return function(){
  114. divReference.classList.add("cascade");
  115. };
  116. }(newDiv)), result * 20);
  117. }
  118. }
  119. /*
  120. * AJAX the current query string to the server, and return its response.
  121. *
  122. * @return {Array} The server's response in the form of `div.result` DOM
  123. * elements, to fill `div#results`.
  124. */
  125. function queryServer(){
  126. var resultDivs = []
  127. for(var result = 0; result < 20; result++){
  128. var newDiv = document.createElement("div");
  129. newDiv.classList.add("result");
  130. newDiv.innerHTML = Math.random();
  131. newDiv.style.textAlign = "center";
  132. newDiv.style.color = "#" + Math.floor(Math.random() *
  133. 16777215).toString(16);
  134. resultDivs.push(newDiv);
  135. }
  136. return resultDivs;
  137. }
  138. /*
  139. * Adds more results to `div#results`.
  140. */
  141. function loadMoreResults(){
  142. results = queryServer();
  143. for(var result = 0; result < results.length; result++){
  144. var newDiv = results[result];
  145. resultsDiv.appendChild(newDiv);
  146. setTimeout(
  147. (function(divReference){
  148. return function(){
  149. divReference.classList.add("cascade");
  150. };
  151. }(newDiv)),
  152. result * 20);
  153. }
  154. }
  155. var searchGroups = [];
  156. var currentSearchGroup = 0;
  157. // Create a new search group.
  158. $("div#add-group").click(function(){
  159. storeSearchGroup();
  160. currentSearchGroup = searchGroups.length;
  161. $("span#current, span#total").text(currentSearchGroup + 1);
  162. });
  163. // Save the current's search group's values, and load the previous one.
  164. $("div#previous-group").click(function(){
  165. console.log(currentSearchGroup);
  166. if(0 < currentSearchGroup){
  167. storeSearchGroup();
  168. currentSearchGroup--;
  169. loadSearchGroup();
  170. $("span#current").text(currentSearchGroup + 1);
  171. }
  172. });
  173. // Save the current's search group's values, and load the next one.
  174. $("div#next-group").click(function(){
  175. console.log(currentSearchGroup);
  176. if(currentSearchGroup < searchGroups.length - 1){
  177. storeSearchGroup();
  178. currentSearchGroup++;
  179. loadSearchGroup();
  180. $("span#current").text(currentSearchGroup + 1);
  181. }
  182. });
  183. /*
  184. * Store the advanced search form's values into the currently selected search
  185. * group object.
  186. */
  187. function storeSearchGroup(){
  188. var searchGroup = {};
  189. var inputs = $("div#advanced-search input[type='text']");
  190. for(var input = 0; input < inputs.length; input++)
  191. if(inputs[input].value.length > 0){
  192. searchGroup[inputs[input].id] = inputs[input].value;
  193. inputs[input].value = "";
  194. }
  195. if(currentSearchGroup < searchGroups.length)
  196. searchGroups[currentSearchGroup] = searchGroup;
  197. else
  198. searchGroups.push(searchGroup);
  199. }
  200. /*
  201. * Load the values belonging to the currently selected search group object into
  202. * the advanced search form.
  203. */
  204. function loadSearchGroup(groupNumber){
  205. for(var inputId in searchGroups[currentSearchGroup]){
  206. var selector = "div#advanced-search input[type='text']#" + inputId;
  207. $(selector).val(searchGroups[currentSearchGroup][inputId]);
  208. }
  209. }