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.
 
 
 
 
 
 

167 lines
5.7 KiB

  1. /*
  2. * @file Manages all advanced search form logic.
  3. */
  4. var searchGroups = $("div#search-groups");
  5. /*
  6. * Load all advanced search form libraries.
  7. */
  8. function loadInputFieldWidgets(){
  9. $(".search-group input#date-last-modified").datepicker();
  10. $(".search-group input#date-created").datepicker();
  11. $(".search-group input#autocomplete").autocomplete({
  12. source: function(request, response){
  13. var matcher = new RegExp(
  14. $.ui.autocomplete.escapeRegex(request.term), "i");
  15. response($.grep(AUTOCOMPLETE_LANGUAGES, function(item){
  16. return matcher.test(item);
  17. }));
  18. }
  19. });
  20. };
  21. loadInputFieldWidgets();
  22. /*
  23. * Set all advanced search form button callbacks.
  24. */
  25. (function setSearchFormCallbacks(){
  26. // Create a new search group, and update the `#sidebar` checklist.
  27. $("button#add-group").click(function(){
  28. $("div#sidebar input[type=checkbox]").prop("checked", false);
  29. searchGroups.children("#selected").removeAttr("id");
  30. var searchGroup = $("<div/>", {
  31. class : "search-group",
  32. id : "selected"
  33. });
  34. searchGroups.append(
  35. searchGroup.append(createSearchGroupInput("language", "languages")));
  36. loadInputFieldWidgets();
  37. $("div#sidebar input[type=checkbox]#language").prop("checked", true);
  38. searchGroups[0].scrollTop = searchGroups[0].scrollHeight;
  39. });
  40. // Remove the currently selected group if it's not the only one, and mark
  41. // one of its siblings as selected.
  42. $("button#remove-group").click(function(){
  43. var currentGroup = $("div.search-group#selected");
  44. if($("div.search-group").length == 1)
  45. return;
  46. else {
  47. var nextGroup = currentGroup.prev();
  48. if(nextGroup.size() == 0)
  49. nextGroup = currentGroup.next();
  50. }
  51. currentGroup.remove();
  52. nextGroup.click();
  53. });
  54. // Select a search group, and update the `#sidebar` checklist accordingly.
  55. $(document).on("click", "div.search-group", function(){
  56. searchGroups.children("#selected").removeAttr("id");
  57. $(this).attr("id", "selected");
  58. $("div#sidebar input[type=checkbox]").prop("checked", false);
  59. $(this).find("input[type=text]").each(function(){
  60. var checkBoxSelector = "div#sidebar input[type=checkbox]";
  61. $(checkBoxSelector + "#" + $(this).attr("class").split(" ")[0]).
  62. prop("checked", true);
  63. })
  64. });
  65. // Toggle the presence of an input field.
  66. $("div#sidebar input[type=checkbox]").click(function(){
  67. var fieldId = $(this).prop("id");
  68. if($(this).is(":checked")){
  69. $("div.search-group#selected").append(
  70. $.parseHTML(createSearchGroupInput(
  71. fieldId, $(this).next("label").children("div").
  72. text())));
  73. loadInputFieldWidgets();
  74. if(fieldId.slice(0, 4) == "date")
  75. $(".search-group#selected ." + fieldId).datepicker();
  76. }
  77. else {
  78. if($(".search-group#selected").children("div").length > 1)
  79. $(".search-group#selected #" + fieldId).remove()
  80. else
  81. $(this).prop("checked", true);
  82. }
  83. searchGroups[0].scrollTop = searchGroups[0].scrollHeight;
  84. });
  85. var previousAdvancedQuery = "";
  86. var searchBar = $("form#search-bar input[name=query]");
  87. window.setInterval(function(){
  88. var currentQuery = assembleQuery();
  89. if(currentQuery != previousAdvancedQuery){
  90. previousAdvancedQuery = currentQuery;
  91. searchBar.val(assembleQuery());
  92. }
  93. }, 1e3 / 15);
  94. }());
  95. /*
  96. * Return an HTML string representing a new input field div in a search group.
  97. *
  98. * @param fieldId The id of the input field div, and its child elements.
  99. * @param name The name to display next to the input field.
  100. */
  101. function createSearchGroupInput(fieldId, name){
  102. var fieldHTML = [
  103. "<div id='" + fieldId + "'>",
  104. "<div class='name'>" + name + "</div>",
  105. "<input class='" + fieldId + "' name='" + fieldId + "'type='text'>",
  106. "<input type='checkbox' name='regex'>",
  107. "<span class='regex'>Regex</span>",
  108. "</div>"
  109. ]
  110. if(fieldId == "language")
  111. fieldHTML[2] = [
  112. "<input id='autocomplete' class='language'",
  113. "name='language' type='text'>"
  114. ].join(" ");
  115. return fieldHTML.join("");
  116. }
  117. /*
  118. * Create a query from advanced-search groups.
  119. */
  120. function assembleQuery(){
  121. var groups = searchGroups.children(".search-group");
  122. var groupQueries = [];
  123. for(var group = 0; group < groups.length; group++){
  124. var inputFields = groups[group].querySelectorAll("input[type=text]");
  125. var regexCheckbox = groups[group].querySelectorAll("input[name=regex]");
  126. var groupQuery = [];
  127. for(var field = 0; field < inputFields.length; field++)
  128. if(inputFields[field].value.length > 0)
  129. groupQuery.push(genFieldQueryString(
  130. inputFields[field], regexCheckbox[field].checked));
  131. if(groupQuery.length > 0)
  132. groupQueries.push(groupQuery.join(" AND "));
  133. }
  134. return groupQueries.join(" OR ");
  135. }
  136. /*
  137. * Generate a processed query string for an input field's value.
  138. *
  139. * @param field (DOM element) An `input[type=text]` element.
  140. * @param hasRegex (boolean) Whether or not the field's value has regex.
  141. */
  142. function genFieldQueryString(field, hasRegex){
  143. var terms = field.value.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"");
  144. var query = field.getAttribute("name") + ":" + (hasRegex?"re:":"") + terms;
  145. return '"' + query + '"';
  146. }