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.
 
 
 
 
 
 

168 lines
8.6 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. FINISH_TYPING_INTERVAL = 650;
  22. searchBar = $("form#search-bar input[type='text']")[0];
  23. resultsDiv = $("div#results")[0];
  24. var typingTimer, lastValue;
  25. //Obtained by parsing python file with pygments
  26. var codeExample = '<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 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</pre></div></td><td class="code"><div class="hll"><pre><span class="sd">&quot;&quot;&quot;</span>\n<span class="sd">Module to contain all the project&#39;s Flask server plumbing.</span>\n<span class="sd">&quot;&quot;&quot;</span>\n\n<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>\n<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">render_template</span><span class="p">,</span> <span class="n">session</span>\n\n<span class="kn">from</span> <span class="nn">bitshift</span> <span class="kn">import</span> <span class="n">assets</span>\n<span class="c"># from bitshift.database import Database</span>\n<span class="c"># from bitshift.query import parse_query</span>\n\n<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>\n<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_object</span><span class="p">(</span><span class="s">&quot;bitshift.config&quot;</span><span class="p">)</span>\n\n<span class="n">app_env</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">jinja_env</span>\n<span class="n">app_env</span><span class="o">.</span><span class="n">line_statement_prefix</span> <span class="o">=</span> <span class="s">&quot;=&quot;</span>\n<span class="n">app_env</span><span class="o">.</span><span class="n">globals</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">assets</span><span class="o">=</span><span class="n">assets</span><span class="p">)</span>\n\n<span class="c"># database = Database()</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">index</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">&quot;index.html&quot;</span><span class="p">)</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/search/&lt;query&gt;&quot;</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>\n <span class="c"># tree = parse_query(query)</span>\n <span class="c"># database.search(tree)</span>\n <span class="k">pass</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/about&quot;</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">about</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">&quot;about.html&quot;</span><span class="p">)</span>\n\n<span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/developers&quot;</span><span class="p">)</span>\n<span class="k">def</span> <span class="nf">developers</span><span class="p">():</span>\n <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">&quot;developers.html&quot;</span><span class="p">)</span>\n\n<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>\n <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>\n</pre></div>\n</td></tr></table>'
  27. searchBar.onkeyup = typingTimer;
  28. // Enable infinite scrolling down the results page.
  29. $(window).scroll(function() {
  30. var searchField = $("div#search-field");
  31. if($(window).scrollTop() + $(window).height() == $(document).height() && searchField.hasClass('partly-visible')){
  32. loadMoreResults();
  33. }
  34. });
  35. // Enable capturing the `enter` key.
  36. $("form#search-bar").submit(function(event){
  37. event.preventDefault();
  38. return false;
  39. });
  40. /*
  41. * Clear the existing timer and set a new one the the user types text into the
  42. * search bar.
  43. */
  44. function typingTimer(event){
  45. clearTimeout(typingTimer);
  46. var enterKeyCode = 13;
  47. if(event.keyCode != enterKeyCode){
  48. if(lastValue != searchBar.value)
  49. typingTimer = setTimeout(finishedTyping, FINISH_TYPING_INTERVAL);
  50. }
  51. else {
  52. event.preventDefault();
  53. finishedTyping();
  54. return false;
  55. }
  56. };
  57. /*
  58. * Callback which queries the server whenver the user stops typing.
  59. *
  60. * Whenever the user doesn't type for a `FINISH_TYPING_INTERVAL` after having
  61. * entered new text in the search bar, send the current query request to the
  62. * server.
  63. */
  64. function finishedTyping(){
  65. lastValue = searchBar.value;
  66. var searchField = $("div#search-field");
  67. clearResults();
  68. if(searchBar.value){
  69. searchField.addClass("partly-visible");
  70. populateResults();
  71. }
  72. else {
  73. searchField.removeClass("partly-visible");
  74. $("div#advanced-search").fadeOut(50);
  75. advancedSearchButton.removeClass("clicked");
  76. }
  77. }
  78. /*
  79. * Removes any child elements of `div#results`.
  80. */
  81. function clearResults(){
  82. while(resultsDiv.firstChild)
  83. resultsDiv.removeChild(resultsDiv.firstChild);
  84. }
  85. /*
  86. * Query the server with the current search string, and populate `div#results`
  87. * with its response.
  88. */
  89. function populateResults(){
  90. var results = queryServer();
  91. for(var result = 0; result < results.length; result++){
  92. var newDiv = results[result];
  93. resultsDiv.appendChild(newDiv);
  94. setTimeout(
  95. (function(divReference){
  96. return function(){
  97. divReference.classList.add("cascade");
  98. };
  99. }(newDiv)), result * 20);
  100. }
  101. }
  102. /*
  103. * AJAX the current query string to the server, and return its response.
  104. *
  105. * @return {Array} The server's response in the form of `div.result` DOM
  106. * elements, to fill `div#results`.
  107. */
  108. function queryServer(){
  109. var resultDivs = []
  110. for(var result = 0; result < 20; result++){
  111. var newDiv = document.createElement("div"),
  112. table = document.createElement("table"),
  113. row = document.createElement("tr"),
  114. sidebar = document.createElement("td"),
  115. codeElt = document.createElement("td"),
  116. meta = document.createElement("td");
  117. newDiv.classList.add("result");
  118. sidebar.id = 'sidebar';
  119. codeElt.id = 'code';
  120. meta.id = 'meta';
  121. sidebar.innerHTML = '';
  122. codeElt.innerHTML = '<div id=tablecontainer>' + codeExample + '</div>';
  123. row.appendChild(sidebar);
  124. row.appendChild(codeElt);
  125. row.appendChild(meta);
  126. table.appendChild(row);
  127. newDiv.appendChild(table);
  128. resultDivs.push(newDiv);
  129. }
  130. return resultDivs;
  131. }
  132. /*
  133. * Adds more results to `div#results`.
  134. */
  135. function loadMoreResults(){
  136. results = queryServer();
  137. for(var result = 0; result < results.length; result++){
  138. var newDiv = results[result];
  139. resultsDiv.appendChild(newDiv);
  140. setTimeout(
  141. (function(divReference){
  142. return function(){
  143. divReference.classList.add("cascade");
  144. };
  145. }(newDiv)),
  146. result * 20);
  147. }
  148. }