Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / file_manager / 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 /**
6  * Search box.
7  *
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}
12  * @constructor
13  */
14 function SearchBox(element, searchButton, noResultMessage) {
15   cr.EventTarget.call(this);
16
17   /**
18    * Autocomplete List.
19    * @type {!SearchBox.AutocompleteList}
20    */
21   this.autocompleteList = new SearchBox.AutocompleteList(element.ownerDocument);
22
23   /**
24    * Root element of the search box.
25    * @type {Element}
26    */
27   this.element = element;
28
29   /**
30    * Search button.
31    * @type {Element}
32    */
33   this.searchButton = searchButton;
34
35   /**
36    * No result message.
37    * @type {Element}
38    */
39   this.noResultMessage = noResultMessage;
40
41   /**
42    * Text input of the search box.
43    * @type {!HTMLInputElement}
44    */
45   this.inputElement = /** @type {!HTMLInputElement} */ (
46       element.querySelector('input'));
47
48   /**
49    * Clear button of the search box.
50    * @type {Element}
51    */
52   this.clearButton = element.querySelector('.clear');
53
54   // Register events.
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(
60       'dragover',
61       this.onDragEnter_.bind(this),
62       true);
63   this.inputElement.ownerDocument.addEventListener(
64       'dragend',
65       this.onDragEnd_.bind(this));
66   this.searchButton.addEventListener(
67       'click',
68       this.onSearchButtonClick_.bind(this));
69   this.clearButton.addEventListener(
70       'click',
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);
76
77   // Append dynamically created element.
78   element.parentNode.appendChild(this.autocompleteList);
79 }
80
81 SearchBox.prototype = {
82   __proto__: cr.EventTarget.prototype
83 };
84
85 /**
86  * Event type.
87  * @enum {string}
88  */
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'
94 };
95
96 /**
97  * Autocomplete list for search box.
98  * @param {Document} document Document.
99  * @constructor
100  * @extends {cr.ui.AutocompleteList}
101  */
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));
109   return self;
110 };
111
112 SearchBox.AutocompleteList.prototype = {
113   __proto__: cr.ui.AutocompleteList.prototype
114 };
115
116 /**
117  * Do nothing when a suggestion is selected.
118  * @override
119  */
120 SearchBox.AutocompleteList.prototype.handleSelectedSuggestion = function() {};
121
122 /**
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:
125  *
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
128  *
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.
132  *
133  * @param {Event} event Event.
134  * @private
135  */
136 SearchBox.AutocompleteList.prototype.onMouseOver_ = function(event) {
137   if (event.target.itemInfo)
138     this.selectedItem = event.target.itemInfo;
139 };
140
141 /**
142  * ListItem element for autocomplete.
143  *
144  * @param {Document} document Document.
145  * @param {Object} item An object representing a suggestion.
146  * @constructor
147  * @private
148  */
149 SearchBox.AutocompleteListItem_ = function(document, item) {
150   var li = new cr.ui.ListItem();
151   li.itemInfo = item;
152
153   var icon = document.createElement('div');
154   icon.className = 'detail-icon';
155
156   var text = document.createElement('div');
157   text.className = 'detail-text';
158
159   if (item.isHeaderItem) {
160     icon.setAttribute('search-icon', '');
161     text.innerHTML =
162         strf('SEARCH_DRIVE_HTML', util.htmlEscape(item.searchQuery));
163   } else {
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;
169   }
170   li.appendChild(icon);
171   li.appendChild(text);
172   return li;
173 };
174
175 /**
176  * Clears the search query.
177  */
178 SearchBox.prototype.clear = function() {
179   this.inputElement.value = '';
180   this.updateStyles_();
181 };
182
183 /**
184  * @private
185  */
186 SearchBox.prototype.onInput_ = function() {
187   this.updateStyles_();
188   cr.dispatchSimpleEvent(this, SearchBox.EventType.TEXT_CHANGE);
189 };
190
191 /**
192  * Handles a focus event of the search box.
193  * @private
194  */
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);
199 };
200
201 /**
202  * Handles a blur event of the search box.
203  * @private
204  */
205 SearchBox.prototype.onBlur_ = function() {
206   this.element.classList.toggle('has-cursor', false);
207   this.inputElement.tabIndex = '-1';
208   this.autocompleteList.detach();
209 };
210
211 /**
212  * Handles a keydown event of the search box.
213  * @param {Event} event
214  * @private
215  */
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)
220     return;
221   this.inputElement.blur();
222 };
223
224 /**
225  * Handles a dragenter event and refuses a drag source of files.
226  * @param {Event} event The dragenter event.
227  * @private
228  */
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';
236 };
237
238 /**
239  * Handles a dragend event.
240  * @private
241  */
242 SearchBox.prototype.onDragEnd_ = function() {
243   this.inputElement.style.pointerEvents = '';
244 };
245
246 /**
247  * Updates styles of the search box.
248  * @private
249  */
250 SearchBox.prototype.updateStyles_ = function() {
251   this.element.classList.toggle('has-text',
252                                 !!this.inputElement.value);
253 };
254
255 /**
256  * @private
257  */
258 SearchBox.prototype.onSearchButtonClick_ = function() {
259   this.inputElement.focus();
260 };
261
262 /**
263  * @private
264  */
265 SearchBox.prototype.onClearButtonClick_ = function() {
266   this.inputElement.value = '';
267   this.onInput_();
268 };