var Index = {};
(function (ns) {
ns.keyLength = 0;
ns.keys = function (obj) {
var result = [];
var key;
for (key in obj) {
result.push(key);
ns.keyLength++;
}
return result;
}
})(Index);
/** Find query string from URL */
var QueryString = function(key) {
if (QueryString.map === undefined) { // only calc once
QueryString.map = {};
var keyVals = window.location.search.split("?").pop().split("&");
keyVals.forEach(function(elem) {
var pair = elem.split("=");
if (pair.length == 2) QueryString.map[pair[0]] = pair[1];
});
}
return QueryString.map[key];
};
$(document).ready(function() {
// Clicking #doc-title returns the user to the root package
$("#doc-title").on("click", function() { document.location = toRoot + "index.html" });
if (QueryString("search") !== undefined) {
$("#index-input").val(QueryString("search"));
searchAll();
}
});
/* Handles all key presses while scrolling around with keyboard shortcuts in search results */
function handleKeyNavigation() {
/** Iterates both back and forth among selected elements */
var EntityIterator = function (litems, ritems) {
var it = this;
this.index = -1;
/** Returns the next entry - if trying to select past last element, it
* returns the last element
*/
it.next = function() {
it.index = Math.min(it.items.length - 1, it.index + 1);
return $(it.items[it.index]);
};
/** Returns the previous entry - will return `undefined` instead if
* selecting up from first element
*/
it.prev = function() {
it.index = Math.max(-1, it.index - 1);
return it.index == -1 ? undefined : $(it.items[it.index]);
};
function safeOffset($elem) {
return $elem.length ? $elem.offset() : { top:0, left:0 }; // offset relative to viewport
}
/** Scroll helper, ensures that the selected elem is inside the viewport */
var Scroller = function ($container) {
scroller = this;
scroller.container = $container;
function compilePattern(query) {
var escaped = query.replace(/([\.\*\+\?\|\(\)\[\]\\])/g, '\\$1');
if (query.toLowerCase() != query) {
// Regexp that matches CamelCase subbits: "BiSe" is
// "[a-z]*Bi[a-z]*Se" and matches "BitSet", "ABitSet", ...
return new RegExp(escaped.replace(/([A-Z])/g,"[a-z]*$1"));
}
else { // if query is all lower case make a normal case insensitive search
return new RegExp(escaped, "i");
}
}
/** Searches packages for entites matching the search query using a regex
*
* @param {[Object]} pack: package being searched
* @param {RegExp} regExp: a regular expression for finding matching entities
*/
function searchPackage(pack, regExp) {
scheduler.add("search", function() {
var entities = Index.PACKAGES[pack];
var matched = [];
var notMatching = [];
/** This function inserts `li` into the `ul` ordered by the li's id
*
* @param {Node} ul: the list in which to insert `li`
* @param {Node} li: item to insert
*/
function insertSorted(ul, li) {
var lis = ul.childNodes;
var beforeLi = null;
for (var i = 0; i < lis.length; i++) {
if (lis[i].id > li.id)
beforeLi = lis[i];
}
// if beforeLi == null, it will be inserted last
ul.insertBefore(li, beforeLi);
}
/** Defines the callback when a package has been searched and searches its
* members
*
* It will search all entities which matched the regExp.
*
* @param {Object} res: this is the searched package. It will contain the map
* from the `searchPackage`function.
* @param {RegExp} regExp
*/
function handleSearchedPackage(res, regExp) {
$("div#search-results").show();
$("#search > span.close-results").show();
$("#search > span#doc-title").hide();
var searchRes = document.getElementById("results-content");
var entityDiv = document.getElementById("entity-results");
if (res.matched.length == 0)
packLink.style.display = "none";
entityDiv.appendChild(packLink);
var ul = document.createElement("ul")
ul.className = "entities";
// Generate html list items from results
res.matched
.map(function(entity) { return listItem(entity, regExp); })
.forEach(function(li) { ul.appendChild(li); });
entityDiv.appendChild(ul);
}
/** Searches an entity asynchronously for regExp matches in an entity's members
*
* @param {Object} entity: the entity to be searched
* @param {Node} ul: the list in which to insert the list item created
* @param {RegExp} regExp
*/
function searchEntity(entity, ul, regExp) {
return new Promise(function(resolve, reject) {
var allMembers =
(entity.members_trait || [])
.concat(entity.members_class || [])
.concat(entity.members_object || [])
var matchingMembers = $.grep(allMembers, function(member, i) {
return regExp.test(member.label);
});
var tail = document.createElement("span");
tail.className = "tail";
tail.appendChild(document.createTextNode(elem.tail));
var li = document.createElement("li");
li.appendChild(kind);
li.appendChild(label);
li.appendChild(tail);
ul.appendChild(li);
});
return res;
});
}
/** Creates a list item representing an entity
*
* @param {Object} entity, the searched entity to be displayed
* @param {RegExp} regExp
* @return {Node} list item containing entity
*/
function listItem(entity, regExp) {
var name = entity.name.split('.').pop()
var nameElem = document.createElement("span");
nameElem.className = "entity";
var ul = document.createElement("ul");
ul.className = "members";
li.appendChild(ul);
return li;
}
/** Searches all packages and entities for the current search string in
* the input field "#textfilter"
*
* Then shows the results in div#search-results
*/
function searchAll() {
scheduler.clear("search"); // clear previous search
maxJobs = 1; // clear previous max
var searchStr = ($("#textfilter input").val() || '').trim();
// Replace ?search=X with current search string if not hosted locally on Chrome
try {
window.history.replaceState({}, "", "?search=" + searchStr);
} catch(e) {}
var memberResults = document.getElementById("member-results");
memberResults.innerHTML = "";
var memberH1 = document.createElement("h1");
memberH1.className = "result-type";
memberH1.innerHTML = "Member results";
memberResults.appendChild(memberH1);
var entityResults = document.getElementById("entity-results");
entityResults.innerHTML = "";
var entityH1 = document.createElement("h1");
entityH1.className = "result-type";
entityH1.innerHTML = "Entity results";
entityResults.appendChild(entityH1);
$("div#results-content").prepend(
$("<span>")
.addClass("search-text")
.append(document.createTextNode(" Showing results for "))
.append($("<span>").addClass("query-str").text(searchStr))
);
var regExp = compilePattern(searchStr);
// Search for all entities matching query
Index
.keys(Index.PACKAGES)
.sort()
.forEach(function(elem) { searchPackage(elem, regExp); })
}
/** Check if user agent is associated with a known mobile browser */
function isMobile() {
return /Android|webOS|Mobi|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
function urlFriendlyEntity(entity) {
var corr = {
'\\+': '$plus',
':': '$colon'
};
for (k in corr)
entity = entity.replace(new RegExp(k, 'g'), corr[k]);
return entity;
}
var maxJobs = 1;
function setProgress() {
var running = scheduler.numberOfJobs("search");
maxJobs = Math.max(maxJobs, running);
var percent = 100 - (running / maxJobs * 100);
var bar = document.getElementById("progress-fill");
bar.style.height = "100%";
bar.style.width = percent + "%";