Skip to content

Commit

Permalink
Basic search is working. Bug-hunting.
Browse files Browse the repository at this point in the history
  • Loading branch information
haasted committed Apr 2, 2015
1 parent 87aba8f commit 630740e
Showing 1 changed file with 123 additions and 30 deletions.
153 changes: 123 additions & 30 deletions jdocenhance.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,32 @@
// - Maintain presence on page if a new package is selected.
// - Explore whether String.prototype.localeCompare is more appropriate for string comparison.

/*
Search logic :
- All lowercase - Prefix-search
- Contains capitals : camel-case search
: Split into "camel-case" fragments, e.g. StrBu turns into [Str, Bu]
- Binary search first fragment
- Brute-search second fragment in the remaining list.
- Inital wild-card : "old style" regexp search
Split everything into fragments?
- Initial search binary, following searches brute-force.
- Exception : "Initial wildcard"-searches : all brute-force, e.g. "*buf"
Examples :
"StrBuf" : [Str, Buf]
"Str*Buf" : [Str, *, Buf]
'strbuf' : [strbuf]
"SB" : [S, B]
// Fragment reg exp?
([A-Z]{1}[a-z]*|\*|[a-z]+)
*/

console.log("Loaded!");

(function() {
console.log("Loading enhanced Javadoc");
var timerObj,
previousSearch, // The search term the last time doSearch() was invoked.
selector, // The selector used to identify each class entry. Varies between javadoc versions.
Expand All @@ -17,18 +41,20 @@
}
searchFieldAnchor.prepend('<input type="text" id="classSearch" style="margin-bottom: 10px" /><br/>');



$('html > head', packageFrame).append('<style>.filtered { display: none; }</style>');
$('html > head', packageFrame).append('<style>.selected { background-color : lightgray; }</style>');

$("#classSearch", packageFrame).keyup(function(event) {
if (event.keyCode == 13 ) { // Enter
goToSelected();
} else if (event.keyCode == 40) { // Down
moveMarker(1);
} else if (event.keyCode == 38) { // Up
moveMarker(-1);
}
});
// $("#classSearch", packageFrame).keyup(function(event) {
// if (event.keyCode == 13 ) { // Enter
// goToSelected();
// } else if (event.keyCode == 40) { // Down
// moveMarker(1);
// } else if (event.keyCode == 38) { // Up
// moveMarker(-1);
// }
// });

// Decide how the Javadoc is structured. Some versions are lists, while others are one massive sequence of anchor tags followed by breaks.
if ( $("li", packageFrame).length > 1000 ) {
Expand All @@ -48,24 +74,65 @@
});

function doSearch() {
console.log("Performing search");
clearTimeout(timerObj);

var search = $("#classSearch", packageFrame).val();
if (search === previousSearch) return;
if (search === previousSearch) {
return
};

console.log("Selector", selector);
var start = binarySearchTop(search, $(selector, packageFrame));
console.log("Found start index ", start);
var end = binarySearchBottom(search, $(selector, packageFrame));
console.log("Found end index ", end);
// The first fragment of the search string decides the search strategy.
var firstFragment = search.match(/([A-Z]{1}[a-z]*|\*|[a-z]+)/);

console.time("Hide");
var startEl = $(selector, packageFrame).eq(start);
startEl.prevAll().addClass("filtered");
if (firstFragment === null || search.trim() === '*') {
$(selector, packageFrame).removeClass("filtered");
return;
}

var endEl = $(selector, packageFrame).eq(end);
endEl.nextAll().addClass("filtered");
firstFragment = firstFragment[0];

// Various search strategies, depending on the search term used
if (firstFragment === '*') {
// Initial wild-card. Do a complete brute-force search.
var regexp = getRegExp(search);
bruteSearch($(selector, packageFrame), regexp);
return;
}

if (firstFragment === search) {
// No camel-case. Do a simple prefix-search.
binarySearch(firstFragment);
return;
}

// Camelcase search. Start binary, filter the remaining brute-force.
binarySearch(firstFragment);
var regexp = getRegExp(search);
bruteSearch($(selector + ":not(.filtered)", packageFrame), regexp);

return;


// Build regexp:
console.time("BruteSearch");
var regexp = getRegExp(search);
bruteSearch($(selector + ":not(.filtered)", packageFrame), regexp);
console.timeEnd("BruteSearch");

// console.time("Find non-filtered (SingleQuery)");
// var s = $(selector + ":not(.filtered)", packageFrame);
// console.log("Size " + s.size());

// console.timeEnd("Find non-filtered (SingleQuery)");


// console.time("Find non-filtered (chained)");

// s = $(selector, packageFrame).not(".filtered");
// console.log("Size " + s.size());

// console.timeEnd("Find non-filtered (chained)");

console.timeEnd("Hide");

// var regexp = getRegExp(search);
// clearSelection();
Expand All @@ -91,6 +158,31 @@
previousSearch = search;
};

function binarySearch(prefix) {
console.time("BinarySearch");
var start = binarySearchTop(prefix, $(selector, packageFrame));
var end = binarySearchBottom(prefix, $(selector, packageFrame));

// TODO Measure potential improvement of including index inside selector string.
var startEl = $(selector, packageFrame).eq(start);
startEl.prevAll().addClass("filtered");

var endEl = $(selector, packageFrame).eq(end);
endEl.nextAll().addClass("filtered");

$(selector, packageFrame).slice(start, end).removeClass("filtered");
console.timeEnd("BinarySearch");
}

function bruteSearch(elements, regexp) {
console.time("BruteSearch");
elements.each(function(idx, el) {
el = $(el);
el.toggleClass("filtered", el.text().match(regexp) === null);
});
console.timeEnd("BruteSearch");
}

function getRegExp(search) { // I do not want to know the cyclomatic complexity of this one ...
var result = "",
camelCase = false;
Expand Down Expand Up @@ -129,7 +221,7 @@
return -1;

var mid = Math.floor((low + high) / 2);
var txt = $(lis[mid]).text().substr(0, prefix.length);
var txt = $(lis[mid]).text().substr(0, prefix.length).toLowerCase();;

if (txt > prefix)
return bsTop(prefix, lis, low, mid - 1);
Expand All @@ -139,14 +231,14 @@

// Verify that the entry before this doesn't match the pattern.
// If it does, continue the search upwards, else return mid.
var txtPrev = $(lis[mid - 1]).text();
var txtPrev = $(lis[mid - 1]).text().toLowerCase();
if (txtPrev.indexOf(prefix) === 0)
return bsTop(prefix, lis, low, mid - 1);

return mid;
}
console.log(items.size());
return bsTop(prefix, items, 0, items.size());

return bsTop(prefix.toLowerCase(), items, 0, items.size());
}

function binarySearchBottom(prefix, items) {
Expand All @@ -155,7 +247,7 @@
return -1;

var mid = Math.floor((low + high) / 2);
var txt = $(lis[mid]).text().substr(0, prefix.length);
var txt = $(lis[mid]).text().substr(0, prefix.length).toLowerCase();

// Explore whether String.prototype.localeCompare is more appropriate for string comparison.
if (txt > prefix)
Expand All @@ -166,13 +258,14 @@

// Verify that the entry after this doesn't match the pattern.
// If it does, continue search the downwards, else return mid.
var txtNext = $(lis[mid + 1]).text();
var txtNext = $(lis[mid + 1]).text().toLowerCase();
if (txtNext.indexOf(prefix) === 0)
return bsBottom(prefix, lis, mid+1, high);

return mid;
}
return bsBottom(prefix, items, 0, items.size());

return bsBottom(prefix.toLowerCase(), items, 0, items.size());
}

function clearSelection () {
Expand Down

0 comments on commit 630740e

Please sign in to comment.