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.

преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. FINISH_TYPING_INTERVAL = 650;
  8. var searchBar = $("form#search-bar input[type='text']")[0];
  9. var resultsDiv = $("div#results")[0];
  10. var typingTimer, lastValue;
  11. /*
  12. * Set all page callbacks.
  13. */
  14. (function setHomePageCallbabacks(){
  15. // Enable infinite scrolling down the results page.
  16. $(window).scroll(function(){
  17. if($(window).scrollTop() + $(window).height() == $(document).height() &&
  18. resultsDiv.querySelectorAll(".result").length > 0)
  19. loadMoreResults();
  20. });
  21. // Toggle the advanced-search form's visibility.
  22. advancedSearchButton.click(function(){
  23. var searchField = $("div#search-field");
  24. if(!advancedSearchDiv.hasClass("visible")){
  25. searchField.addClass("partly-visible");
  26. advancedSearchDiv.fadeIn(500).addClass("visible");
  27. advancedSearchButton.addClass("clicked");
  28. }
  29. else {
  30. advancedSearchDiv.fadeOut(300).removeClass("visible");
  31. advancedSearchButton.removeClass("clicked");
  32. if($("div#results .result").length == 0)
  33. searchField.removeClass("partly-visible");
  34. }
  35. });
  36. // Enable capturing the `enter` key.
  37. $("form#search-bar").submit(function(event){
  38. event.preventDefault();
  39. return false;
  40. });
  41. searchBar.onkeyup = typingTimer;
  42. }());
  43. //Obtained by parsing python file with pygments
  44. 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="highlight"><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="hll"><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><span class="hll"><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</span>\n<span class="hll"><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><span class="hll"><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><span class="hll"><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</span>\n<span class="c"># database = Database()</span>\n\n<span class="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">)</span>\n</span><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="hll"><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><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="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/about&quot;</span><span class="p">)</span>\n</span><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="hll"><span class="nd">@app.route</span><span class="p">(</span><span class="s">&quot;/developers&quot;</span><span class="p">)</span>\n</span><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="hll"> <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</span></pre></div>\n</td></tr></table>'
  45. searchBar.onkeyup = typingTimer;
  46. var testCodelet = {
  47. 'url': 'https://github.com/earwig/bitshift/blob/develop/app.py',
  48. 'filename': 'app.py',
  49. 'language': 'python',
  50. 'date_created': 'May 10, 2014',
  51. 'date_modified': '2 days ago',
  52. 'origin': ['GitHub', 'https://github.com', ''],
  53. 'authors': ['sevko', 'earwig'],
  54. 'html_code': codeExample
  55. };
  56. // Enable infinite scrolling down the results page.
  57. $(window).scroll(function() {
  58. var searchField = $("div#search-field");
  59. if($(window).scrollTop() + $(window).height() == $(document).height() && searchField.hasClass('partly-visible')){
  60. loadMoreResults();
  61. }
  62. });
  63. /*
  64. * Clear the existing timer and set a new one the the user types text into the
  65. * search bar.
  66. */
  67. function typingTimer(event){
  68. clearTimeout(typingTimer);
  69. var enterKeyCode = 13;
  70. if(event.keyCode != enterKeyCode){
  71. if(lastValue != searchBar.value)
  72. typingTimer = setTimeout(finishedTyping, FINISH_TYPING_INTERVAL);
  73. }
  74. else {
  75. event.preventDefault();
  76. finishedTyping();
  77. return false;
  78. }
  79. };
  80. /*
  81. * Callback which queries the server whenver the user stops typing.
  82. *
  83. * Whenever the user doesn't type for a `FINISH_TYPING_INTERVAL` after having
  84. * entered new text in the search bar, send the current query request to the
  85. * server.
  86. */
  87. function finishedTyping(){
  88. lastValue = searchBar.value;
  89. var searchField = $("div#search-field");
  90. clearResults();
  91. if(searchBar.value){
  92. searchField.addClass("partly-visible");
  93. populateResults();
  94. }
  95. else {
  96. searchField.removeClass("partly-visible");
  97. $("div#advanced-search").fadeOut(50);
  98. advancedSearchButton.removeClass("clicked");
  99. }
  100. }
  101. /*
  102. * Removes any child elements of `div#results`.
  103. */
  104. function clearResults(){
  105. while(resultsDiv.firstChild)
  106. resultsDiv.removeChild(resultsDiv.firstChild);
  107. }
  108. /*
  109. * Query the server with the current search string, and populate `div#results`
  110. * with its response.
  111. */
  112. function populateResults(){
  113. var results = queryServer();
  114. for(var result = 0; result < results.length; result++){
  115. var newDiv = results[result];
  116. resultsDiv.appendChild(newDiv);
  117. setTimeout(
  118. (function(divReference){
  119. return function(){
  120. divReference.classList.add("cascade");
  121. };
  122. }(newDiv)), result * 20);
  123. }
  124. }
  125. /*
  126. * Create a result element based upon a codelet instance.
  127. *
  128. * @return {Element} The result element.
  129. */
  130. function createResult(codelet) {
  131. //Level 1
  132. var newDiv = document.createElement("div"),
  133. table = document.createElement("table"),
  134. row = document.createElement("tr");
  135. //Level 2
  136. var displayInfo = document.createElement("div"),
  137. codeElt = document.createElement("td"),
  138. hiddenInfoContainer = document.createElement("td"),
  139. hiddenInfo = document.createElement("div");
  140. //Level 3
  141. var title = document.createElement("span"),
  142. site = document.createElement("span"),
  143. nextMatch = document.createElement("a"),
  144. prevMatch = document.createElement("a"),
  145. dateModified = document.createElement("div"),
  146. language = document.createElement("div"),
  147. dateCreated = document.createElement("div"),
  148. authors = document.createElement("div");
  149. //Classes and ID's
  150. newDiv.classList.add('result');
  151. displayInfo.id = 'display-info';
  152. codeElt.id = 'code';
  153. hiddenInfo.id = 'hidden-info';
  154. title.id = 'title';
  155. site.id = 'site';
  156. nextMatch.id = 'next-match';
  157. nextMatch.href = '#';
  158. prevMatch.id = 'prev-match';
  159. prevMatch.href = '#';
  160. dateModified.id = 'date-modified';
  161. language.id = 'language';
  162. dateCreated.id = 'date-created';
  163. authors.id = 'authors';
  164. //Add the bulk of the html
  165. title.innerHTML = 'File <a href="' + codelet.url + '">'
  166. + codelet.filename + '</a>';
  167. site.innerHTML = 'on <a href="' + codelet.origin[1] + '">' + codelet.origin[0] +'</a>';
  168. nextMatch.innerHTML = 'next match';
  169. prevMatch.innerHTML = 'prev match';
  170. language.innerHTML = 'Language: <span>' + codelet.language + '</span>';
  171. dateModified.innerHTML = 'Last modified: <span>' + codelet.date_modified + '</span>';
  172. // Needs to be changed from int to string on the server
  173. dateCreated.innerHTML = 'Created: <span>' + codelet.date_created + '</span>';
  174. var authorsHtml = 'Authors: <span>';
  175. codelet.authors.forEach(function(a, i) {
  176. if (i == codelet.authors.length - 1)
  177. authorsHtml += '<a href=#>' + a + ' </a>';
  178. else
  179. authorsHtml += '<a href=#>' + a + ' </a>, ';
  180. });
  181. authors.innerHTML = authorsHtml;
  182. // Needs to be processed on the server
  183. codeElt.innerHTML = '<div id=tablecontainer>' + codelet.html_code + '</div>';
  184. var matches = codeElt.querySelectorAll('.hll');
  185. $.each(matches, function(i, a) {
  186. a.id = 'match_' + i;
  187. });
  188. //Event binding
  189. $(codeElt).hover(function(e) {
  190. $(row).addClass('display-all');
  191. });
  192. $(newDiv).on('transitionend', function(e) {
  193. $(codeElt).one('mouseleave', function(e) {
  194. $(row).removeClass('display-all');
  195. });
  196. });
  197. var cur_match = -1;
  198. var newMatch = function(e) {
  199. var $code = $(newDiv).find('#tablecontainer'),
  200. $match = $code.find('#match_' + cur_match);
  201. $code.scrollTop($code.scrollTop() - $code.height() / 2 +
  202. $match.position().top + $match.height() / 2);
  203. $match.effect("highlight", {}, 750)
  204. }
  205. $(nextMatch).click(function(e) {
  206. e.stopPropagation()
  207. cur_match = cur_match >= matches.length - 1 ? 0 : cur_match + 1;
  208. newMatch();
  209. });
  210. $(prevMatch).click(function(e) {
  211. e.stopPropagation()
  212. cur_match = cur_match <= 0 ? matches.length - 1 : cur_match - 1;
  213. newMatch();
  214. });
  215. //Finish and append elements to parent elements
  216. hiddenInfo.appendChild(dateCreated);
  217. hiddenInfo.appendChild(dateModified);
  218. hiddenInfo.appendChild(language);
  219. hiddenInfo.appendChild(authors);
  220. hiddenInfoContainer.appendChild(hiddenInfo);
  221. row.appendChild(codeElt);
  222. row.appendChild(hiddenInfoContainer);
  223. table.appendChild(row);
  224. displayInfo.appendChild(title);
  225. displayInfo.appendChild(site);
  226. displayInfo.appendChild(prevMatch);
  227. displayInfo.appendChild(nextMatch);
  228. newDiv.appendChild(displayInfo);
  229. newDiv.appendChild(table);
  230. return newDiv;
  231. }
  232. /*
  233. * AJAX the current query string to the server, and return its response.
  234. *
  235. * @return {Array} The server's response in the form of `div.result` DOM
  236. * elements, to fill `div#results`.
  237. */
  238. function queryServer(){
  239. var resultDivs = []
  240. for(var result = 0; result < 20; result++){
  241. var newDiv = createResult(testCodelet);
  242. resultDivs.push(newDiv);
  243. }
  244. return resultDivs;
  245. }
  246. /*
  247. * Adds more results to `div#results`.
  248. */
  249. function loadMoreResults(){
  250. results = queryServer();
  251. for(var result = 0; result < results.length; result++){
  252. var newDiv = results[result];
  253. resultsDiv.appendChild(newDiv);
  254. setTimeout(
  255. (function(divReference){
  256. return function(){
  257. divReference.classList.add("cascade");
  258. };
  259. }(newDiv)),
  260. result * 20);
  261. }
  262. }