home *** CD-ROM | disk | FTP | other *** search
- // Copyright 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- // =============================================================================
- // Util functions
- // =============================================================================
-
- /**
- * The maximum number of suggestions to show.
- * @type {number}
- * @const
- */
- var MAX_SUGGESTIONS_TO_SHOW = 5;
-
- /**
- * The omnibox input value during the last onnativesuggestions event.
- * @type {string}
- */
- var lastInputValue = '';
-
- /**
- * 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>}
- */
-
- var restrictedIds = [];
-
- /**
- * The index of the currently selected suggestion or -1 if none are selected.
- * @type {number}
- */
- var selectedIndex = -1;
-
- /**
- * 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.
- */
- function addSuggestionToBox(suggestion, box, select) {
- var suggestionDiv = document.createElement('div');
- suggestionDiv.classList.add('suggestion');
- if (select)
- suggestionDiv.classList.add('selected');
-
- var contentsContainer = document.createElement('div');
- contentsContainer.className = 'contents';
- var contents = suggestion.combinedNode;
- contentsContainer.appendChild(contents);
- suggestionDiv.appendChild(contentsContainer);
- var restrictedId = suggestion.rid;
- suggestionDiv.onclick = function() {
- handleSuggestionClick(restrictedId);
- };
-
- restrictedIds.push(restrictedId);
- box.appendChild(suggestionDiv);
- }
-
- /**
- * Renders the input suggestions.
- * @param {Array} nativeSuggestions An array of native suggestions to render.
- */
- function renderSuggestions(nativeSuggestions) {
- var box = document.createElement('div');
- box.id = 'suggestionsBox';
- $('suggestions-box-container').appendChild(box);
-
- for (var i = 0, length = nativeSuggestions.length;
- i < Math.min(MAX_SUGGESTIONS_TO_SHOW, length); ++i) {
- // Select the first suggestion.
- addSuggestionToBox(nativeSuggestions[i], box, i == 0);
- }
- }
-
- /**
- * Clears the suggestions being displayed.
- */
- function clearSuggestions() {
- $('suggestions-box-container').innerHTML = '';
- restrictedIds = [];
- selectedIndex = -1;
- }
-
- /**
- * @return {integer} The height of the dropdown.
- */
- function getDropdownHeight() {
- return $('suggestions-box-container').offsetHeight;
- }
-
- /**
- * 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.
- */
- function updateSelectedSuggestion(increment) {
- var numSuggestions = restrictedIds.length;
- if (!numSuggestions)
- return;
-
- var oldSelection = $('suggestionsBox').querySelector('.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);
- } else {
- var newSelection = $('suggestionsBox').querySelector(
- '.suggestion:nth-of-type(' + (selectedIndex + 1) + ')');
- newSelection.classList.add('selected');
- apiHandle.setRestrictedValue(restrictedIds[selectedIndex]);
- }
- }
-
- // =============================================================================
- // Handlers / API stuff
- // =============================================================================
-
- /**
- * @return {Object} the handle to the searchBox API.
- */
- function getApiObjectHandle() {
- if (window.cideb)
- return window.cideb;
- if (window.navigator && window.navigator.searchBox)
- return window.navigator.searchBox;
- if (window.chrome && window.chrome.searchBox)
- return window.chrome.searchBox;
- return null;
- }
-
- /**
- * chrome.searchBox.onnativesuggestions implementation.
- */
- function handleNativeSuggestions() {
- // This can't be done in setUpApi(), because apiHandle.font/fontSize
- // isn't available yet.
- var suggestionStyleNode = $('suggestionStyle');
- if (!suggestionStyleNode)
- appendSuggestionStyles();
-
- var apiHandle = getApiObjectHandle();
-
- // Used to workaround repeated undesired asynchronous onnativesuggestions
- // events and the fact that when a suggestion is clicked, the omnibox unfocus
- // can cause onnativesuggestions to fire, preventing the suggestion onclick
- // from registering.
- if (lastInputValue == apiHandle.value && $('suggestionsBox')) {
- return;
- }
- lastInputValue = apiHandle.value;
-
- clearSuggestions();
- var nativeSuggestions = apiHandle.nativeSuggestions;
- if (nativeSuggestions.length) {
- nativeSuggestions.sort(function(a, b) {
- return b.rankingData.relevance - a.rankingData.relevance;
- });
- renderSuggestions(nativeSuggestions);
- selectedIndex = 0;
- apiHandle.setRestrictedAutocompleteText(
- nativeSuggestions[selectedIndex].rid);
- }
-
- var height = getDropdownHeight();
- apiHandle.show(2, height);
- }
-
- /**
- * Appends a style node for suggestion properties that depend on apiHandle.
- */
- function appendSuggestionStyles() {
- var apiHandle = getApiObjectHandle();
- var style = document.createElement('style');
- style.type = 'text/css';
- style.id = 'suggestionStyle';
- style.textContent =
- '.suggestion {' +
- ' -webkit-margin-start: ' + apiHandle.startMargin + 'px;' +
- ' -webkit-margin-end: ' + apiHandle.endMargin + 'px;' +
- ' font: ' + apiHandle.fontSize + 'px "' + apiHandle.font + '";' +
- '}';
- document.querySelector('head').appendChild(style);
- }
-
- /**
- * Handles suggestion clicks.
- * @param {integer} restrictedId The restricted id of the suggestion being
- * clicked.
- */
- function handleSuggestionClick(restrictedId) {
- clearSuggestions();
- getApiObjectHandle().navigateContentWindow(restrictedId);
- }
-
- /**
- * chrome.searchBox.onkeypress implementation.
- * @param {Object} e The key being pressed.
- */
- function handleKeyPress(e) {
- switch (e.keyCode) {
- case 38: // Up arrow
- updateSelectedSuggestion(false);
- break;
- case 40: // Down arrow
- updateSelectedSuggestion(true);
- break;
- }
- }
-
- /**
- * chrome.searchBox.onsubmit implementation.
- */
- function onSubmit() {
- }
-
- /**
- * Sets up the searchBox API.
- */
- function setUpApi() {
- var apiHandle = getApiObjectHandle();
- apiHandle.onnativesuggestions = handleNativeSuggestions;
- apiHandle.onkeypress = handleKeyPress;
- apiHandle.onsubmit = onSubmit;
- }
-
- document.addEventListener('DOMContentLoaded', setUpApi);
-