| 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;
|
| +}
|
| +
|
| +/**
|
| + * 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);
|
| + 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 = '';
|
| + 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) + ')');
|
| + 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';
|
| + 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);
|
|
|