WebInspector.SuggestBoxDelegate = function()
{
}
WebInspector.SuggestBoxDelegate.prototype = {
applySuggestion: function(suggestion, isIntermediateSuggestion) { },
acceptSuggestion: function() { },
}
WebInspector.SuggestBox = function(suggestBoxDelegate, anchorElement, className)
{
this._suggestBoxDelegate = suggestBoxDelegate;
this._anchorElement = anchorElement;
this._length = 0;
this._selectedIndex = -1;
this._selectedElement = null;
this._boundOnScroll = this._onScrollOrResize.bind(this, true);
this._boundOnResize = this._onScrollOrResize.bind(this, false);
window.addEventListener("scroll", this._boundOnScroll, true);
window.addEventListener("resize", this._boundOnResize, true);
this._bodyElement = anchorElement.ownerDocument.body;
this._element = anchorElement.ownerDocument.createElement("div");
this._element.className = "suggest-box " + (className || "");
this._element.addEventListener("mousedown", this._onBoxMouseDown.bind(this), true);
this.containerElement = this._element.createChild("div", "container");
this.contentElement = this.containerElement.createChild("div", "content");
}
WebInspector.SuggestBox.prototype = {
visible: function()
{
return !!this._element.parentElement;
},
_onScrollOrResize: function(isScroll, event)
{
if (isScroll && this._element.isAncestor(event.target) || !this.visible())
return;
this._updateBoxPosition(this._anchorBox);
},
_updateBoxPosition: function(anchorBox)
{
this._anchorBox = anchorBox;
this.contentElement.style.display = "inline-block";
document.body.appendChild(this.contentElement);
this.contentElement.positionAt(0, 0);
var contentWidth = this.contentElement.offsetWidth;
var contentHeight = this.contentElement.offsetHeight;
this.contentElement.style.display = "block";
this.containerElement.appendChild(this.contentElement);
const spacer = 6;
const suggestBoxPaddingX = 21;
const suggestBoxPaddingY = 2;
var maxWidth = document.body.offsetWidth - anchorBox.x - spacer;
var width = Math.min(contentWidth, maxWidth - suggestBoxPaddingX) + suggestBoxPaddingX;
var paddedWidth = contentWidth + suggestBoxPaddingX;
var boxX = anchorBox.x;
if (width < paddedWidth) {
maxWidth = document.body.offsetWidth - spacer;
width = Math.min(contentWidth, maxWidth - suggestBoxPaddingX) + suggestBoxPaddingX;
boxX = document.body.offsetWidth - width;
}
var boxY;
var aboveHeight = anchorBox.y;
var underHeight = document.body.offsetHeight - anchorBox.y - anchorBox.height;
var maxHeight = Math.max(underHeight, aboveHeight) - spacer;
var height = Math.min(contentHeight, maxHeight - suggestBoxPaddingY) + suggestBoxPaddingY;
if (underHeight >= aboveHeight) {
boxY = anchorBox.y + anchorBox.height;
this._element.removeStyleClass("above-anchor");
this._element.addStyleClass("under-anchor");
} else {
boxY = anchorBox.y - height;
this._element.removeStyleClass("under-anchor");
this._element.addStyleClass("above-anchor");
}
this._element.positionAt(boxX, boxY);
this._element.style.width = width + "px";
this._element.style.height = height + "px";
},
_onBoxMouseDown: function(event)
{
event.preventDefault();
},
hide: function()
{
if (!this.visible())
return;
this._element.parentElement.removeChild(this._element);
delete this._selectedElement;
},
removeFromElement: function()
{
window.removeEventListener("scroll", this._boundOnScroll, true);
window.removeEventListener("resize", this._boundOnResize, true);
this.hide();
},
_applySuggestion: function(text, isIntermediateSuggestion)
{
if (!this.visible() || !(text || this._selectedElement))
return false;
var suggestion = text || this._selectedElement.textContent;
if (!suggestion)
return false;
this._suggestBoxDelegate.applySuggestion(suggestion, isIntermediateSuggestion);
return true;
},
acceptSuggestion: function(text)
{
var result = this._applySuggestion(text, false);
this.hide();
if (!result)
return false;
this._suggestBoxDelegate.acceptSuggestion();
return true;
},
_selectClosest: function(shift, isCircular)
{
if (!this._length)
return false;
var index = this._selectedIndex + shift;
if (isCircular)
index = (this._length + index) % this._length;
else
index = Number.constrain(index, 0, this._length - 1);
this._selectItem(index);
this._applySuggestion(undefined, true);
return true;
},
_onItemMouseDown: function(text, event)
{
this.acceptSuggestion(text);
event.consume(true);
},
_createItemElement: function(prefix, text)
{
var element = document.createElement("div");
element.className = "suggest-box-content-item source-code";
element.tabIndex = -1;
if (prefix && prefix.length && !text.indexOf(prefix)) {
var prefixElement = element.createChild("span", "prefix");
prefixElement.textContent = prefix;
var suffixElement = element.createChild("span", "suffix");
suffixElement.textContent = text.substring(prefix.length);
} else {
var suffixElement = element.createChild("span", "suffix");
suffixElement.textContent = text;
}
element.addEventListener("mousedown", this._onItemMouseDown.bind(this, text), false);
return element;
},
_updateItems: function(items, selectedIndex, userEnteredText)
{
this._length = items.length;
this.contentElement.removeChildren();
for (var i = 0; i < items.length; ++i) {
var item = items[i];
var currentItemElement = this._createItemElement(userEnteredText, item);
this.contentElement.appendChild(currentItemElement);
}
this._selectedElement = null;
if (typeof selectedIndex === "number")
this._selectItem(selectedIndex);
},
_selectItem: function(index)
{
if (this._selectedElement)
this._selectedElement.classList.remove("selected");
this._selectedIndex = index;
this._selectedElement = this.contentElement.children[index];
this._selectedElement.classList.add("selected");
this._selectedElement.scrollIntoViewIfNeeded(false);
},
_canShowBox: function(completions, canShowForSingleItem, userEnteredText)
{
if (!completions || !completions.length)
return false;
if (completions.length > 1)
return true;
return canShowForSingleItem && completions[0] !== userEnteredText;
},
_rememberRowCountPerViewport: function()
{
if (!this.contentElement.firstChild)
return;
this._rowCountPerViewport = Math.floor(this.containerElement.offsetHeight / this.contentElement.firstChild.offsetHeight);
},
updateSuggestions: function(anchorBox, completions, selectedIndex, canShowForSingleItem, userEnteredText)
{
if (this._canShowBox(completions, canShowForSingleItem, userEnteredText)) {
this._updateItems(completions, selectedIndex, userEnteredText);
this._updateBoxPosition(anchorBox);
if (!this.visible())
this._bodyElement.appendChild(this._element);
this._rememberRowCountPerViewport();
} else
this.hide();
},
upKeyPressed: function()
{
return this._selectClosest(-1, true);
},
downKeyPressed: function()
{
return this._selectClosest(1, true);
},
pageUpKeyPressed: function()
{
return this._selectClosest(-this._rowCountPerViewport, false);
},
pageDownKeyPressed: function()
{
return this._selectClosest(this._rowCountPerViewport, false);
},
enterKeyPressed: function()
{
var hasSelectedItem = !!this._selectedElement;
this.acceptSuggestion();
return hasSelectedItem;
},
tabKeyPressed: function()
{
return this.enterKeyPressed();
}
}