- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / file_manager / foreground / js / ui / search_box.js
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.
4
5 'use strict';
6
7 /**
8  * Search box.
9  *
10  * @param {element} element Root element of the search box.
11  * @constructor
12  */
13 function SearchBox(element) {
14   /**
15    * Autocomplete List.
16    * @type {AutocompleteList}
17    */
18   this.autocompleteList = new SearchBox.AutocompleteList(element.ownerDocument);
19
20   /**
21    * Root element of the search box.
22    * @type {HTMLElement}
23    */
24   this.element = element;
25
26   /**
27    * Text input of the search box.
28    * @type {HTMLElement}
29    */
30   this.inputElement = element.querySelector('input');
31
32   /**
33    * Clear button of the search box.
34    * @type {HTMLElement}
35    */
36   this.clearButton = element.querySelector('.clear');
37
38   /**
39    * Text measure.
40    * @type {TextMeasure}
41    * @private
42    */
43   this.textMeasure_ = new TextMeasure(this.inputElement);
44
45   Object.freeze(this);
46
47   // Register events.
48   this.inputElement.addEventListener('input', this.updateStyles_.bind(this));
49   this.inputElement.addEventListener('keydown', this.onKeyDown_.bind(this));
50   this.inputElement.addEventListener('focus', this.onFocus_.bind(this));
51   this.inputElement.addEventListener('blur', this.onBlur_.bind(this));
52   element.querySelector('.icon').addEventListener(
53       'click', this.onIconClick_.bind(this));
54   element.parentNode.appendChild(this.autocompleteList);
55 }
56
57 /**
58  * Autocomplete list for search box.
59  * @param {HTMLDocument} document Document.
60  * @constructor
61  */
62 SearchBox.AutocompleteList = function(document) {
63   var self = cr.ui.AutocompleteList.call(this);
64   self.__proto__ = SearchBox.AutocompleteList.prototype;
65   self.id = 'autocomplete-list';
66   self.autoExpands = true;
67   self.itemConstructor = SearchBox.AutocompleteListItem_.bind(null, document);
68   self.addEventListener('mouseover', self.onMouseOver_.bind(self));
69   return self;
70 };
71
72 SearchBox.AutocompleteList.prototype = {
73   __proto__: cr.ui.AutocompleteList.prototype
74 };
75
76 /**
77  * Do nothing when a suggestion is selected.
78  * @override
79  */
80 SearchBox.AutocompleteList.prototype.handleSelectedSuggestion = function() {};
81
82 /**
83  * Change the selection by a mouse over instead of just changing the
84  * color of moused over element with :hover in CSS. Here's why:
85  *
86  * 1) The user selects an item A with up/down keys (item A is highlighted)
87  * 2) Then the user moves the cursor to another item B
88  *
89  * If we just change the color of moused over element (item B), both
90  * the item A and B are highlighted. This is bad. We should change the
91  * selection so only the item B is highlighted.
92  *
93  * @param {Event} event Event.
94  * @private
95  */
96 SearchBox.AutocompleteList.prototype.onMouseOver_ = function(event) {
97   if (event.target.itemInfo)
98     this.selectedItem = event.target.itemInfo;
99 };
100
101 /**
102  * ListItem element for autocomple.
103  *
104  * @param {HTMLDocument} document Document.
105  * @param {Object} item An object representing a suggestion.
106  * @constructor
107  * @private
108  */
109 SearchBox.AutocompleteListItem_ = function(document, item) {
110   var li = new cr.ui.ListItem();
111   li.itemInfo = item;
112
113   var icon = document.createElement('div');
114   icon.className = 'detail-icon';
115
116   var text = document.createElement('div');
117   text.className = 'detail-text';
118
119   if (item.isHeaderItem) {
120     icon.setAttribute('search-icon');
121     text.innerHTML =
122         strf('SEARCH_DRIVE_HTML', util.htmlEscape(item.searchQuery));
123   } else {
124     var iconType = FileType.getIcon(item.entry);
125     icon.setAttribute('file-type-icon', iconType);
126     // highlightedBaseName is a piece of HTML with meta characters properly
127     // escaped. See the comment at fileBrowserPrivate.searchDriveMetadata().
128     text.innerHTML = item.highlightedBaseName;
129   }
130   li.appendChild(icon);
131   li.appendChild(text);
132   return li;
133 };
134
135 /**
136  * Updates the size related style.
137  */
138 SearchBox.prototype.updateSizeRelatedStyle = function() {
139   // Hide the search box if there is not enough space.
140   this.element.classList.toggle(
141       'too-short',
142       this.element.clientWidth < 100);
143 };
144
145 /**
146  * Clears the search query.
147  */
148 SearchBox.prototype.clear = function() {
149   this.inputElement.value = '';
150   this.updateStyles_();
151 };
152
153 /**
154  * Handles a focus event of the search box.
155  * @private
156  */
157 SearchBox.prototype.onFocus_ = function() {
158   this.element.classList.toggle('has-cursor', true);
159   this.inputElement.tabIndex = '99';  // See: go/filesapp-tabindex.
160   this.autocompleteList.attachToInput(this.inputElement);
161 };
162
163 /**
164  * Handles a blur event of the search box.
165  * @private
166  */
167 SearchBox.prototype.onBlur_ = function() {
168   this.element.classList.toggle('has-cursor', false);
169   this.inputElement.tabIndex = '-1';
170   this.autocompleteList.detach();
171 };
172
173 /**
174  * Handles a keydown event of the search box.
175  * @private
176  */
177 SearchBox.prototype.onKeyDown_ = function() {
178   // Handle only Esc key now.
179   if (event.keyCode != 27 || this.inputElement.value)
180     return;
181   this.inputElement.blur();
182 };
183
184 /**
185  * Handles a click event of the search icon.
186  * @private
187  */
188 SearchBox.prototype.onIconClick_ = function() {
189   this.inputElement.focus();
190 };
191
192 /**
193  * Updates styles of the search box.
194  * @private
195  */
196 SearchBox.prototype.updateStyles_ = function() {
197   this.element.classList.toggle('has-text',
198                                  !!this.inputElement.value);
199   var width = this.textMeasure_.getWidth(this.inputElement.value) +
200       16 /* Extra space to allow leeway. */;
201   this.inputElement.style.width = width + 'px';
202 };