1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 * @param {Element} element Root element of the search box.
9 * @param {Element} searchButton Search button.
10 * @param {Element} noResultMessage Message element for the empty result.
11 * @extends {cr.EventTarget}
14 function SearchBox(element, searchButton, noResultMessage) {
15 cr.EventTarget.call(this);
19 * @type {!SearchBox.AutocompleteList}
21 this.autocompleteList = new SearchBox.AutocompleteList(element.ownerDocument);
24 * Root element of the search box.
27 this.element = element;
33 this.searchButton = searchButton;
39 this.noResultMessage = noResultMessage;
42 * Text input of the search box.
43 * @type {!HTMLInputElement}
45 this.inputElement = /** @type {!HTMLInputElement} */ (
46 element.querySelector('input'));
49 * Clear button of the search box.
52 this.clearButton = element.querySelector('.clear');
55 this.inputElement.addEventListener('input', this.onInput_.bind(this));
56 this.inputElement.addEventListener('keydown', this.onKeyDown_.bind(this));
57 this.inputElement.addEventListener('focus', this.onFocus_.bind(this));
58 this.inputElement.addEventListener('blur', this.onBlur_.bind(this));
59 this.inputElement.ownerDocument.addEventListener(
61 this.onDragEnter_.bind(this),
63 this.inputElement.ownerDocument.addEventListener(
65 this.onDragEnd_.bind(this));
66 this.searchButton.addEventListener(
68 this.onSearchButtonClick_.bind(this));
69 this.clearButton.addEventListener(
71 this.onClearButtonClick_.bind(this));
72 var dispatchItemSelect =
73 cr.dispatchSimpleEvent.bind(cr, this, SearchBox.EventType.ITEM_SELECT);
74 this.autocompleteList.handleEnterKeydown = dispatchItemSelect;
75 this.autocompleteList.addEventListener('mouseDown', dispatchItemSelect);
77 // Append dynamically created element.
78 element.parentNode.appendChild(this.autocompleteList);
81 SearchBox.prototype = {
82 __proto__: cr.EventTarget.prototype
89 SearchBox.EventType = {
90 // Dispatched when the text in the search box is changed.
91 TEXT_CHANGE: 'textchange',
92 // Dispatched when the item in the auto complete list is selected.
93 ITEM_SELECT: 'itemselect'
97 * Autocomplete list for search box.
98 * @param {Document} document Document.
100 * @extends {cr.ui.AutocompleteList}
102 SearchBox.AutocompleteList = function(document) {
103 var self = cr.ui.AutocompleteList.call(this);
104 self.__proto__ = SearchBox.AutocompleteList.prototype;
105 self.id = 'autocomplete-list';
106 self.autoExpands = true;
107 self.itemConstructor = SearchBox.AutocompleteListItem_.bind(null, document);
108 self.addEventListener('mouseover', self.onMouseOver_.bind(self));
112 SearchBox.AutocompleteList.prototype = {
113 __proto__: cr.ui.AutocompleteList.prototype
117 * Do nothing when a suggestion is selected.
120 SearchBox.AutocompleteList.prototype.handleSelectedSuggestion = function() {};
123 * Change the selection by a mouse over instead of just changing the
124 * color of moused over element with :hover in CSS. Here's why:
126 * 1) The user selects an item A with up/down keys (item A is highlighted)
127 * 2) Then the user moves the cursor to another item B
129 * If we just change the color of moused over element (item B), both
130 * the item A and B are highlighted. This is bad. We should change the
131 * selection so only the item B is highlighted.
133 * @param {Event} event Event.
136 SearchBox.AutocompleteList.prototype.onMouseOver_ = function(event) {
137 if (event.target.itemInfo)
138 this.selectedItem = event.target.itemInfo;
142 * ListItem element for autocomplete.
144 * @param {Document} document Document.
145 * @param {Object} item An object representing a suggestion.
149 SearchBox.AutocompleteListItem_ = function(document, item) {
150 var li = new cr.ui.ListItem();
153 var icon = document.createElement('div');
154 icon.className = 'detail-icon';
156 var text = document.createElement('div');
157 text.className = 'detail-text';
159 if (item.isHeaderItem) {
160 icon.setAttribute('search-icon', '');
162 strf('SEARCH_DRIVE_HTML', util.htmlEscape(item.searchQuery));
164 var iconType = FileType.getIcon(item.entry);
165 icon.setAttribute('file-type-icon', iconType);
166 // highlightedBaseName is a piece of HTML with meta characters properly
167 // escaped. See the comment at fileManagerPrivate.searchDriveMetadata().
168 text.innerHTML = item.highlightedBaseName;
170 li.appendChild(icon);
171 li.appendChild(text);
176 * Clears the search query.
178 SearchBox.prototype.clear = function() {
179 this.inputElement.value = '';
180 this.updateStyles_();
186 SearchBox.prototype.onInput_ = function() {
187 this.updateStyles_();
188 cr.dispatchSimpleEvent(this, SearchBox.EventType.TEXT_CHANGE);
192 * Handles a focus event of the search box.
195 SearchBox.prototype.onFocus_ = function() {
196 this.element.classList.toggle('has-cursor', true);
197 this.inputElement.tabIndex = '99'; // See: go/filesapp-tabindex.
198 this.autocompleteList.attachToInput(this.inputElement);
202 * Handles a blur event of the search box.
205 SearchBox.prototype.onBlur_ = function() {
206 this.element.classList.toggle('has-cursor', false);
207 this.inputElement.tabIndex = '-1';
208 this.autocompleteList.detach();
212 * Handles a keydown event of the search box.
213 * @param {Event} event
216 SearchBox.prototype.onKeyDown_ = function(event) {
217 event = /** @type {KeyboardEvent} */ (event);
218 // Handle only Esc key now.
219 if (event.keyCode != 27 || this.inputElement.value)
221 this.inputElement.blur();
225 * Handles a dragenter event and refuses a drag source of files.
226 * @param {Event} event The dragenter event.
229 SearchBox.prototype.onDragEnter_ = function(event) {
230 event = /** @type {DragEvent} */ (event);
231 // For normal elements, they does not accept drag drop by default, and accept
232 // it by using event.preventDefault. But input elements accept drag drop
233 // by default. So disable the input element here to prohibit drag drop.
234 if (event.dataTransfer.types.indexOf('text/plain') === -1)
235 this.inputElement.style.pointerEvents = 'none';
239 * Handles a dragend event.
242 SearchBox.prototype.onDragEnd_ = function() {
243 this.inputElement.style.pointerEvents = '';
247 * Updates styles of the search box.
250 SearchBox.prototype.updateStyles_ = function() {
251 this.element.classList.toggle('has-text',
252 !!this.inputElement.value);
258 SearchBox.prototype.onSearchButtonClick_ = function() {
259 this.inputElement.focus();
265 SearchBox.prototype.onClearButtonClick_ = function() {
266 this.inputElement.value = '';