Index: chrome/browser/resources/local_omnibox_popup/local_omnibox_popup.js |
diff --git a/chrome/browser/resources/local_omnibox_popup/local_omnibox_popup.js b/chrome/browser/resources/local_omnibox_popup/local_omnibox_popup.js |
index 7923115c690facb71b83cf16ee668b73f2b02b4d..ee62f24b445b0ce2551acdb022c2f47fd3e99f1f 100644 |
--- a/chrome/browser/resources/local_omnibox_popup/local_omnibox_popup.js |
+++ b/chrome/browser/resources/local_omnibox_popup/local_omnibox_popup.js |
@@ -7,10 +7,6 @@ |
* features are not supported on the server. |
*/ |
-// ========================================================== |
-// Enums. |
-// ========================================================== |
- |
/** |
* Possible behaviors for navigateContentWindow. |
* @enum {number} |
@@ -27,10 +23,6 @@ var WindowOpenDisposition = { |
*/ |
var MIDDLE_MOUSE_BUTTON = 1; |
-// ============================================================================= |
-// Util functions |
-// ============================================================================= |
- |
/** |
* The maximum number of suggestions to show. |
* @type {number} |
@@ -47,101 +39,78 @@ var MAX_SUGGESTIONS_TO_SHOW = 5; |
var INLINE_SUGGESTION_THRESHOLD = 1200; |
/** |
- * Suggestion provider type corresponding to a verbatim URL suggestion. |
+ * The color code for a display URL. |
* @type {string} |
* @const |
*/ |
-var VERBATIM_URL_TYPE = 'url-what-you-typed'; |
+var URL_COLOR = '#093'; |
/** |
- * Suggestion provider type corresponding to a verbatim search suggestion. |
+ * The color code for a suggestion title. |
* @type {string} |
* @const |
*/ |
-var VERBATIM_SEARCH_TYPE = 'search-what-you-typed'; |
+var TITLE_COLOR = '#666'; |
/** |
- * The omnibox input value during the last onnativesuggestions event. |
+ * A top position which is off-screen. |
* @type {string} |
+ * @const |
*/ |
-var lastInputValue = ''; |
+var OFF_SCREEN = '-1000px'; |
/** |
- * The ordered restricted ids of the currently displayed suggestions. Since the |
- * suggestions contain the user's personal data (browser history) the searchBox |
- * API embeds the content of the suggestion in a shadow dom, and assigns a |
- * random restricted id to each suggestion which is accessible to the JS. |
- * @type {Array.<number>} |
+ * The expected origin of a suggestion iframe. |
+ * @type {string} |
+ * @const |
*/ |
- |
-var restrictedIds = []; |
+var SUGGESTION_ORIGIN = 'chrome-search://suggestion'; |
/** |
- * The index of the currently selected suggestion or -1 if none are selected. |
- * @type {number} |
+ * Suggestion provider type corresponding to a verbatim URL suggestion. |
+ * @type {string} |
+ * @const |
*/ |
-var selectedIndex = -1; |
+var VERBATIM_URL_TYPE = 'url-what-you-typed'; |
/** |
- * Shortcut for document.getElementById. |
- * @param {string} id of the element. |
- * @return {HTMLElement} with the id. |
+ * Suggestion provider type corresponding to a verbatim search suggestion. |
+ * @type {string} |
+ * @const |
*/ |
-function $(id) { |
- return document.getElementById(id); |
-} |
+var VERBATIM_SEARCH_TYPE = 'search-what-you-typed'; |
/** |
- * Displays a suggestion. |
- * @param {Object} suggestion The suggestion to render. |
- * @param {HTMLElement} box The html element to add the suggestion to. |
- * @param {boolean} select True to select the selection. |
+ * The displayed suggestions. |
+ * @type {SuggestionsBox} |
*/ |
-function addSuggestionToBox(suggestion, box, select) { |
- var suggestionDiv = document.createElement('div'); |
- suggestionDiv.classList.add('suggestion'); |
- suggestionDiv.classList.toggle('selected', select); |
- suggestionDiv.classList.toggle('search', suggestion.is_search); |
- |
- var suggestionIframe = document.createElement('iframe'); |
- suggestionIframe.className = 'contents'; |
- suggestionIframe.src = suggestion.destination_url; |
- suggestionIframe.id = suggestion.rid; |
- suggestionDiv.appendChild(suggestionIframe); |
- |
- restrictedIds.push(suggestion.rid); |
- box.appendChild(suggestionDiv); |
-} |
+var activeSuggestionsBox; |
/** |
- * Renders the input suggestions. |
- * @param {Array} nativeSuggestions An array of native suggestions to render. |
+ * The suggestions being rendered. |
+ * @type {SuggestionsBox} |
*/ |
-function renderSuggestions(nativeSuggestions) { |
- var box = document.createElement('div'); |
- box.id = 'suggestionsBox'; |
- $('suggestions-box-container').appendChild(box); |
+var pendingSuggestionsBox; |
- for (var i = 0, length = nativeSuggestions.length; |
- i < Math.min(MAX_SUGGESTIONS_TO_SHOW, length); ++i) { |
- addSuggestionToBox(nativeSuggestions[i], box, i == selectedIndex); |
- } |
-} |
+/** |
+ * A pool of iframes to display suggestions. |
+ * @type {IframePool} |
+ */ |
+var iframePool; |
/** |
- * Clears the suggestions being displayed. |
+ * A serial number for the next suggestions rendered. |
+ * @type {number} |
*/ |
-function clearSuggestions() { |
- $('suggestions-box-container').innerHTML = ''; |
- restrictedIds = []; |
- selectedIndex = -1; |
-} |
+var nextRequestId = 0; |
/** |
- * @return {number} The height of the dropdown. |
+ * Shortcut for document.querySelector. |
+ * @param {string} selector A selector to query the desired element. |
+ * @return {HTMLElement} matching selector. |
*/ |
-function getDropdownHeight() { |
- return $('suggestions-box-container').offsetHeight; |
+function $(selector) { |
+ return document.querySelector(selector); |
} |
/** |
@@ -160,44 +129,331 @@ function shouldSelectSuggestion(suggestion, inVerbatimMode) { |
} |
/** |
- * Updates selectedIndex, bounding it between -1 and the total number of |
- * of suggestions - 1 (looping as necessary), and selects the corresponding |
- * suggestion. |
- * @param {boolean} increment True to increment the selected suggestion, false |
- * to decrement. |
+ * Extract the desired navigation behavior from a click button. |
+ * @param {number} button The Event#button property of a click event. |
+ * @return {WindowOpenDisposition} The desired behavior for |
+ * navigateContentWindow. |
*/ |
-function updateSelectedSuggestion(increment) { |
- var numSuggestions = restrictedIds.length; |
- if (!numSuggestions) |
- return; |
+function getDispositionFromClickButton(button) { |
+ if (button == MIDDLE_MOUSE_BUTTON) |
+ return WindowOpenDisposition.NEW_BACKGROUND_TAB; |
+ return WindowOpenDisposition.CURRENT_TAB; |
+} |
+ |
+/** |
samarth
2013/04/02 23:26:58
Not sure what style Chrome JS prefers, but I would
Jered
2013/04/03 18:49:33
Yeah, ideally we'd have a compiler of some sort...
|
+ * Manages a pool of chrome-search iframes. |
+ * @constructor |
+ */ |
+function IframePool() { |
+ this.iframes_ = []; |
+} |
+ |
+/** |
+ * Initializes the pool with blank result template iframes, positioned off |
+ * screen. |
+ */ |
+IframePool.prototype.init = function() { |
+ for (var i = 0; i < 2 * MAX_SUGGESTIONS_TO_SHOW; i++) { |
+ var iframe = document.createElement('iframe'); |
+ iframe.className = 'contents'; |
+ iframe.id = 'suggestion-text-' + i; |
+ iframe.src = 'chrome-search://suggestion/result.html'; |
+ iframe.style.top = OFF_SCREEN; |
+ iframe.addEventListener('mouseover', hover(iframe.id), false); |
samarth
2013/04/02 23:26:58
It's not clear at all that hover() returns a funct
Jered
2013/04/03 18:49:33
Done.
|
+ iframe.addEventListener('mouseout', unhover(iframe.id), false); |
+ document.body.appendChild(iframe); |
+ this.iframes_[i] = iframe; |
+ } |
+}; |
+ |
+/** |
+ * Retrieves a free suggestion iframe from the pool. |
+ * @return {Element} An iframe suitable for holding a suggestion. |
+ */ |
+IframePool.prototype.get = function() { |
+ return this.iframes_.pop(); |
+}; |
+ |
+/** |
+ * Releases a suggestion iframe back into the pool. |
+ * @param {Element} iframe The iframe to return to the pool. |
+ */ |
+IframePool.prototype.release = function(iframe) { |
+ this.iframes_.push(iframe); |
+ iframe.style.top = OFF_SCREEN; |
+}; |
+ |
+/** |
+ * Displays a suggestions box. |
+ * @param {string} inputValue The user text which prompted these suggestions. |
+ * @param {Array.<Object>} suggestions Suggestions to display. |
+ * @param {number} selectedIndex The index of the suggestion selected. |
+ * @constructor |
+ */ |
+function SuggestionsBox(inputValue, suggestions, selectedIndex) { |
+ this.inputValue_ = inputValue; |
+ this.suggestions_ = suggestions; |
+ this.selectedIndex_ = selectedIndex; |
+ |
+ /** |
+ * The index of the suggestion currently under the mouse pointer. |
+ * @type {number} |
+ * @private |
+ */ |
+ this.hoveredIndex_ = -1; |
+ |
+ /** |
+ * A stamp to distinguish this suggestions box from others. |
+ * @type {number} |
+ * @private |
+ */ |
+ this.requestId_ = nextRequestId++; |
+ |
+ /** |
+ * The ordered iframes showing suggestions in this suggestions box. |
+ * @type {Array.<Element>} |
+ * @private |
+ */ |
+ this.iframes_ = []; |
+ |
+ /** |
+ * The ordered restricted ids for suggestions in this suggestions box. |
+ * @type {Array.<number>} |
+ * @private |
+ */ |
+ this.restrictedIds_ = []; |
+ |
+ /** |
+ * An embedded search API handle. |
+ * @type {Object} |
+ * @private |
+ */ |
+ this.apiHandle_ = getApiObjectHandle(); |
+ |
+ /** |
+ * The CSS class of the container for these suggestions. Initially pending, |
+ * then active once shown. |
+ * @type {string} |
+ */ |
+ this.containerClass = 'pending-container'; |
+} |
+ |
+/** |
+ * Starts rendering new suggestions. |
+ */ |
+SuggestionsBox.prototype.load = function() { |
+ // Create a placeholder DOM in the invisible container. |
+ $('.' + this.containerClass).innerHTML = ''; |
samarth
2013/04/02 23:26:58
This file uses a mix of raw DOM operations (see If
Jered
2013/04/03 18:49:33
Leaving as is based on our offline conversation, s
|
+ var box = document.createElement('div'); |
+ box.className = 'suggestionsBox'; |
+ $('.' + this.containerClass).appendChild(box); |
+ var framesToLoad = {}; |
+ for (var i = 0, suggestion; suggestion = this.suggestions_[i]; i++) { |
+ var div = document.createElement('div'); |
+ div.classList.add('suggestion'); |
+ div.classList.toggle('selected', i == this.selectedIndex_); |
+ div.classList.toggle('search', suggestion.is_search); |
+ box.appendChild(div); |
+ // Reserve an iframe for each suggestion. |
+ this.iframes_[i] = iframePool.get(); |
+ this.restrictedIds_[i] = suggestion.rid; |
+ framesToLoad[this.iframes_[i].id] = suggestion.rid; |
+ } |
+ // Ask the loader iframe to populate the iframes just reserved. |
+ var loadRequest = { |
+ 'load': framesToLoad, |
+ 'requestId': this.requestId_, |
+ 'style': { |
+ 'urlColor': URL_COLOR, |
+ 'titleColor': TITLE_COLOR |
+ } |
+ }; |
+ $('#suggestion-loader').contentWindow.postMessage(loadRequest, |
+ SUGGESTION_ORIGIN); |
+}; |
+ |
+/** |
+ * Releases suggestion iframes and ignores a load done message for the current |
+ * suggestions. |
+ */ |
+SuggestionsBox.prototype.releaseIframes = function() { |
+ for (var i = 0; i < this.iframes_.length; i++) { |
+ iframePool.release(this.iframes_[i]); |
+ } |
+ this.responseId = -1; |
+}; |
+ |
+/** |
+ * Returns whether the given request should be displayed. |
+ * @param {number} requestId The number of the request that finished rendering. |
+ * @return {boolean} True if should display, false if not. |
+ */ |
+SuggestionsBox.prototype.shouldShow = function(requestId) { |
+ return requestId == this.requestId_; |
+}; |
- var oldSelection = $('suggestionsBox').querySelector('.selected'); |
+/** |
+ * Moves iframes into position. |
+ */ |
+SuggestionsBox.prototype.showIframes = function() { |
+ var divs = document.querySelectorAll('.' + this.containerClass + |
+ ' .suggestion'); |
+ // Note: This may be called before margins are ready. In that case, |
+ // suggestion iframes will initially be too large and then size down |
+ // onresize. |
+ var startMargin = this.apiHandle_.startMargin; |
+ var totalMargin = window.innerWidth - this.apiHandle_.width; |
+ for (var i = 0; i < divs.length && i < this.iframes_.length; i++) { |
+ // Add in the expected parent offset and the top margin. |
+ this.iframes_[i].style.top = (divs[i].offsetTop + 4) + 'px'; |
+ this.iframes_[i].style[this.apiHandle_.isRtl ? 'right' : 'left'] = |
+ startMargin + 'px'; |
+ this.iframes_[i].style.width = '-webkit-calc(100% - ' + |
+ (totalMargin + 26) + 'px)'; |
+ } |
+}; |
+ |
+/** |
+ * Selects the suggestion before the current selection. |
+ */ |
+SuggestionsBox.prototype.selectPrevious = function() { |
+ var numSuggestions = this.suggestions_.length; |
+ this.selectedIndex_--; |
+ if (this.selectedIndex_ < -1) |
+ this.selectedIndex_ = -1; |
+ this.redrawSelection_(); |
+ this.redrawHover_(); |
+}; |
+ |
+/** |
+ * Selects the suggestion after the current selection. |
+ */ |
+SuggestionsBox.prototype.selectNext = function() { |
+ var numSuggestions = this.suggestions_.length; |
+ this.selectedIndex_++; |
+ if (this.selectedIndex_ > numSuggestions - 1) |
+ this.selectedIndex_ = numSuggestions - 1; |
+ this.redrawSelection_(); |
+ this.redrawHover_(); |
+}; |
+ |
+/** |
+ * Redraws the selected suggestion. |
+ * @private |
+ */ |
+SuggestionsBox.prototype.redrawSelection_ = function() { |
+ var oldSelection = $('.' + this.containerClass + ' .selected'); |
if (oldSelection) |
oldSelection.classList.remove('selected'); |
- |
- if (increment) |
- selectedIndex = ++selectedIndex > numSuggestions - 1 ? -1 : selectedIndex; |
- else |
- selectedIndex = --selectedIndex < -1 ? numSuggestions - 1 : selectedIndex; |
- var apiHandle = getApiObjectHandle(); |
- if (selectedIndex == -1) { |
- apiHandle.setValue(lastInputValue); |
+ if (this.selectedIndex_ == -1) { |
+ this.apiHandle_.setValue(this.inputValue_); |
} else { |
- var newSelection = $('suggestionsBox').querySelector( |
- '.suggestion:nth-of-type(' + (selectedIndex + 1) + ')'); |
+ var newSelection = $('.' + this.containerClass + |
+ ' .suggestion:nth-of-type(' + (this.selectedIndex_ + 1) + ')'); |
newSelection.classList.add('selected'); |
- apiHandle.setRestrictedValue(restrictedIds[selectedIndex]); |
+ this.apiHandle_.setRestrictedValue( |
+ this.suggestions_[this.selectedIndex_].rid); |
} |
+}; |
+ |
+/** |
+ * Returns the restricted id of the iframe clicked. |
+ * @param {Window} iframeWindow The window of the iframe that was clicked. |
+ * @return {number?} The restricted id clicked or null if none. |
+ */ |
+SuggestionsBox.prototype.getClickTarget = function(iframeWindow) { |
+ for (var i = 0; i < this.iframes_.length; ++i) |
+ if (this.iframes_[i].contentWindow == iframeWindow) |
+ return this.restrictedIds_[i]; |
+ return null; |
+}; |
+ |
+/** |
+ * Called when the user hovers on the specified iframe. |
+ * @param {string} iframeId The id of the iframe hovered. |
+ */ |
+SuggestionsBox.prototype.hover = function(iframeId) { |
+ this.hoveredIndex_ = -1; |
+ for (var i = 0; i < this.iframes_.length; ++i) { |
+ if (this.iframes_[i].id == iframeId) { |
+ this.hoveredIndex_ = i; |
+ break; |
+ } |
+ } |
+ this.redrawHover_(); |
+}; |
+ |
+/** |
+ * Called when the user unhovers the specified iframe. |
+ * @param {string} iframeId The id of the iframe hovered. |
+ */ |
+SuggestionsBox.prototype.unhover = function(iframeId) { |
+ for (var i = 0; i < this.iframes_.length; ++i) { |
+ if (this.iframes_[i].id == iframeId && this.hoveredIndex_ == i) { |
+ this.hoveredIndex_ = -1; |
+ break; |
+ } |
+ } |
+ this.redrawHover_(); |
+}; |
+ |
+/** |
+ * Clears the current hover. |
+ */ |
+SuggestionsBox.prototype.clearHover = function() { |
+ this.hoveredIndex_ = -1; |
+ this.redrawHover_(); |
+}; |
+ |
+/** |
+ * Redraws the mouse hover background. |
+ * @private |
+ */ |
+SuggestionsBox.prototype.redrawHover_ = function() { |
+ if (this.hoveredIndex_ == -1) { |
+ var divs = document.querySelectorAll('.' + this.containerClass + |
+ ' .suggestion'); |
+ for (var i = 0; i < divs.length; i++) |
+ divs[i].classList.remove('hovered'); |
+ } else if (this.hoveredIndex_ != this.selectedIndex_) { |
+ var newHover = $('.' + this.containerClass + |
+ ' .suggestion:nth-of-type(' + (this.hoveredIndex_ + 1) + ')'); |
samarth
2013/04/02 23:26:58
A lot of code like this could be cleaned up if the
Jered
2013/04/03 18:49:33
Done. I still found it cleaner to have separate re
|
+ newHover.classList.add('hovered'); |
+ } |
+}; |
+ |
+/** |
+ * Clears the currently active suggestions and shows pending suggestions. |
+ */ |
+function makePendingSuggestionsActive() { |
+ if (activeSuggestionsBox) |
+ activeSuggestionsBox.releaseIframes(); |
+ activeSuggestionsBox = pendingSuggestionsBox; |
+ pendingSuggestionsBox = null; |
+ var oldActiveContainer = $('.active-container'); |
+ $('.pending-container').className = 'active-container'; |
+ oldActiveContainer.className = 'pending-container'; |
+ activeSuggestionsBox.containerClass = 'active-container'; |
samarth
2013/04/02 23:26:58
This is a little weird. The suggestions box is al
Jered
2013/04/03 18:49:33
Done, sort of. I'm not sure this is less confusing
|
+ activeSuggestionsBox.showIframes(); |
+ var height = $('.active-container').offsetHeight; |
+ getApiObjectHandle().showOverlay(height); |
} |
-// ============================================================================= |
-// Handlers / API stuff |
-// ============================================================================= |
+/** |
+ * Hides the active suggestions box. |
+ */ |
+function hideActiveSuggestions() { |
+ getApiObjectHandle().showOverlay(0); |
+ $('.active-container').innerHTML = ''; |
+ if (activeSuggestionsBox) |
+ activeSuggestionsBox.releaseIframes(); |
+ activeSuggestionsBox = null; |
+} |
/** |
* @return {Object} the handle to the searchBox API. |
*/ |
- function getApiObjectHandle() { |
+function getApiObjectHandle() { |
if (window.cideb) |
return window.cideb; |
if (window.navigator && window.navigator.embeddedSearch && |
@@ -213,22 +469,28 @@ function updateSelectedSuggestion(increment) { |
* Updates suggestions in response to a onchange or onnativesuggestions call. |
*/ |
function updateSuggestions() { |
+ if (pendingSuggestionsBox) { |
+ pendingSuggestionsBox.releaseIframes(); |
+ pendingSuggestionsBox = null; |
+ } |
var apiHandle = getApiObjectHandle(); |
- lastInputValue = apiHandle.value; |
- |
- clearSuggestions(); |
- var nativeSuggestions = apiHandle.nativeSuggestions; |
- if (nativeSuggestions.length) { |
- nativeSuggestions.sort(function(a, b) { |
+ var inputValue = apiHandle.value; |
+ var suggestions = apiHandle.nativeSuggestions; |
+ if (!inputValue || !suggestions.length) { |
+ hideActiveSuggestions(); |
+ return; |
+ } |
+ if (suggestions.length) { |
+ suggestions.sort(function(a, b) { |
return b.rankingData.relevance - a.rankingData.relevance; |
}); |
- if (shouldSelectSuggestion(nativeSuggestions[0], apiHandle.verbatim)) |
+ var selectedIndex = -1; |
+ if (shouldSelectSuggestion(suggestions[0], apiHandle.verbatim)) |
selectedIndex = 0; |
- renderSuggestions(nativeSuggestions); |
+ pendingSuggestionsBox = new SuggestionsBox(inputValue, |
+ suggestions.slice(0, MAX_SUGGESTIONS_TO_SHOW), selectedIndex); |
+ pendingSuggestionsBox.load(); |
} |
- |
- var height = getDropdownHeight(); |
- apiHandle.showOverlay(height); |
} |
/** |
@@ -251,91 +513,107 @@ function appendSuggestionStyles() { |
(window.innerWidth - apiHandle.width - startMargin) + 'px;' + |
' font: ' + apiHandle.fontSize + 'px "' + apiHandle.font + '";' + |
'}'; |
- document.querySelector('head').appendChild(style); |
+ $('head').appendChild(style); |
+ if (activeSuggestionsBox) |
+ activeSuggestionsBox.showIframes(); |
window.removeEventListener('resize', appendSuggestionStyles); |
} |
/** |
- * Extract the desired navigation behavior from a click button. |
- * @param {number} button The Event#button property of a click event. |
- * @return {WindowOpenDisposition} The desired behavior for |
- * navigateContentWindow. |
+ * Makes keys navigate through suggestions. |
+ * @param {Object} e The key being pressed. |
*/ |
-function getDispositionFromClickButton(button) { |
- if (button == MIDDLE_MOUSE_BUTTON) |
- return WindowOpenDisposition.NEW_BACKGROUND_TAB; |
- return WindowOpenDisposition.CURRENT_TAB; |
+function handleKeyPress(e) { |
+ if (activeSuggestionsBox) { |
+ switch (e.keyCode) { |
+ case 38: // Up arrow |
+ activeSuggestionsBox.selectPrevious(); |
+ break; |
+ case 40: // Down arrow |
+ activeSuggestionsBox.selectNext(); |
+ break; |
+ } |
+ } |
} |
/** |
- * Handles suggestion clicks. |
- * @param {number} restrictedId The restricted id of the suggestion being |
- * clicked. |
- * @param {number} button The Event#button property of a click event. |
- * |
+ * Gets a function to call when an iframe is hovered. |
+ * @param {string} id The iframe id. |
+ * @return {function()} A function to call when an iframe is hovered. |
*/ |
-function handleSuggestionClick(restrictedId, button) { |
- clearSuggestions(); |
- getApiObjectHandle().navigateContentWindow( |
- restrictedId, getDispositionFromClickButton(button)); |
+function hover(id) { |
+ return function() { |
+ if (activeSuggestionsBox) |
+ activeSuggestionsBox.hover(id); |
+ }; |
} |
/** |
- * chrome.searchBox.onkeypress implementation. |
- * @param {Object} e The key being pressed. |
+ * Gets a function to call when an iframe is unhovered. |
+ * @param {string} id The iframe id. |
+ * @return {function()} A function to call when an iframe is unhovered. |
*/ |
-function handleKeyPress(e) { |
- switch (e.keyCode) { |
- case 38: // Up arrow |
- updateSelectedSuggestion(false); |
- break; |
- case 40: // Down arrow |
- updateSelectedSuggestion(true); |
- break; |
+function unhover(id) { |
+ return function() { |
+ if (activeSuggestionsBox) |
+ activeSuggestionsBox.unhover(id); |
} |
} |
/** |
- * Handles the postMessage calls from the result iframes. |
- * @param {Object} message The message containing details of clicks the iframes. |
+ * Handles postMessage calls from suggestion iframes. |
+ * @param {Object} message A notification that all iframes are done loading or |
+ * that an iframe was clicked. |
*/ |
function handleMessage(message) { |
- if (message.origin != 'null' || !message.data || |
- message.data.eventType != 'click') { |
+ if (message.origin != SUGGESTION_ORIGIN) |
return; |
- } |
- var iframes = document.getElementsByClassName('contents'); |
- for (var i = 0; i < iframes.length; ++i) { |
- if (iframes[i].contentWindow == message.source) { |
- handleSuggestionClick(parseInt(iframes[i].id, 10), |
- message.data.button); |
- break; |
+ if ('loaded' in message.data) { |
+ if (pendingSuggestionsBox && |
+ pendingSuggestionsBox.shouldShow(message.data.loaded)) { |
+ makePendingSuggestionsActive(); |
+ } |
+ } else if ('click' in message.data) { |
+ if (activeSuggestionsBox) { |
+ var targetId = activeSuggestionsBox.getClickTarget(message.source); |
+ if (targetId != null) { |
+ hideActiveSuggestions(); |
+ getApiObjectHandle().navigateContentWindow(targetId, |
+ getDispositionFromClickButton(message.data.click)); |
+ } |
} |
} |
} |
/** |
- * chrome.searchBox.embeddedSearch.onsubmit implementation. |
+ * Clears hover when window is blurred. |
*/ |
-function onSubmit() { |
+function clearHover() { |
+ if (activeSuggestionsBox) |
+ activeSuggestionsBox.clearHover(); |
} |
/** |
- * Sets up the searchBox API. |
+ * Sets up the embedded search API and creates suggestion iframes. |
*/ |
-function setUpApi() { |
+function init() { |
+ iframePool = new IframePool(); |
+ iframePool.init(); |
var apiHandle = getApiObjectHandle(); |
apiHandle.onnativesuggestions = updateSuggestions; |
apiHandle.onchange = updateSuggestions; |
apiHandle.onkeypress = handleKeyPress; |
- apiHandle.onsubmit = onSubmit; |
- $('suggestions-box-container').dir = apiHandle.rtl ? 'rtl' : 'ltr'; |
+ // Instant checks for this handler to be bound. |
+ apiHandle.onsubmit = function() {}; |
+ $('.active-container').dir = apiHandle.rtl ? 'rtl' : 'ltr'; |
+ $('.pending-container').dir = apiHandle.rtl ? 'rtl' : 'ltr'; |
// Delay adding these styles until the window width is available. |
window.addEventListener('resize', appendSuggestionStyles); |
if (apiHandle.nativeSuggestions.length) |
- handleNativeSuggestions(); |
+ updateSuggestions(); |
} |
-document.addEventListener('DOMContentLoaded', setUpApi); |
+document.addEventListener('DOMContentLoaded', init); |
window.addEventListener('message', handleMessage, false); |
+window.addEventListener('blur', clearHover, false); |