Upstream version 7.35.144.0
[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   this.inputElement.ownerDocument.addEventListener('dragover',
53                                                    this.onDragEnter_.bind(this),
54                                                    true);
55   this.inputElement.ownerDocument.addEventListener('dragend',
56                                                    this.onDragEnd_.bind(this),
57                                                    true);
58   element.querySelector('.icon').addEventListener(
59       'click', this.onIconClick_.bind(this));
60   element.parentNode.appendChild(this.autocompleteList);
61 }
62
63 /**
64  * Autocomplete list for search box.
65  * @param {HTMLDocument} document Document.
66  * @constructor
67  */
68 SearchBox.AutocompleteList = function(document) {
69   var self = cr.ui.AutocompleteList.call(this);
70   self.__proto__ = SearchBox.AutocompleteList.prototype;
71   self.id = 'autocomplete-list';
72   self.autoExpands = true;
73   self.itemConstructor = SearchBox.AutocompleteListItem_.bind(null, document);
74   self.addEventListener('mouseover', self.onMouseOver_.bind(self));
75   return self;
76 };
77
78 SearchBox.AutocompleteList.prototype = {
79   __proto__: cr.ui.AutocompleteList.prototype
80 };
81
82 /**
83  * Do nothing when a suggestion is selected.
84  * @override
85  */
86 SearchBox.AutocompleteList.prototype.handleSelectedSuggestion = function() {};
87
88 /**
89  * Change the selection by a mouse over instead of just changing the
90  * color of moused over element with :hover in CSS. Here's why:
91  *
92  * 1) The user selects an item A with up/down keys (item A is highlighted)
93  * 2) Then the user moves the cursor to another item B
94  *
95  * If we just change the color of moused over element (item B), both
96  * the item A and B are highlighted. This is bad. We should change the
97  * selection so only the item B is highlighted.
98  *
99  * @param {Event} event Event.
100  * @private
101  */
102 SearchBox.AutocompleteList.prototype.onMouseOver_ = function(event) {
103   if (event.target.itemInfo)
104     this.selectedItem = event.target.itemInfo;
105 };
106
107 /**
108  * ListItem element for autocomple.
109  *
110  * @param {HTMLDocument} document Document.
111  * @param {Object} item An object representing a suggestion.
112  * @constructor
113  * @private
114  */
115 SearchBox.AutocompleteListItem_ = function(document, item) {
116   var li = new cr.ui.ListItem();
117   li.itemInfo = item;
118
119   var icon = document.createElement('div');
120   icon.className = 'detail-icon';
121
122   var text = document.createElement('div');
123   text.className = 'detail-text';
124
125   if (item.isHeaderItem) {
126     icon.setAttribute('search-icon', '');
127     text.innerHTML =
128         strf('SEARCH_DRIVE_HTML', util.htmlEscape(item.searchQuery));
129   } else {
130     var iconType = FileType.getIcon(item.entry);
131     icon.setAttribute('file-type-icon', iconType);
132     // highlightedBaseName is a piece of HTML with meta characters properly
133     // escaped. See the comment at fileBrowserPrivate.searchDriveMetadata().
134     text.innerHTML = item.highlightedBaseName;
135   }
136   li.appendChild(icon);
137   li.appendChild(text);
138   return li;
139 };
140
141 /**
142  * Updates the size related style.
143  */
144 SearchBox.prototype.updateSizeRelatedStyle = function() {
145   // Hide the search box if there is not enough space.
146   this.element.classList.toggle(
147       'too-short',
148       this.element.clientWidth < 100);
149 };
150
151 /**
152  * Clears the search query.
153  */
154 SearchBox.prototype.clear = function() {
155   this.inputElement.value = '';
156   this.updateStyles_();
157 };
158
159 /**
160  * Handles a focus event of the search box.
161  * @private
162  */
163 SearchBox.prototype.onFocus_ = function() {
164   this.element.classList.toggle('has-cursor', true);
165   this.inputElement.tabIndex = '99';  // See: go/filesapp-tabindex.
166   this.autocompleteList.attachToInput(this.inputElement);
167 };
168
169 /**
170  * Handles a blur event of the search box.
171  * @private
172  */
173 SearchBox.prototype.onBlur_ = function() {
174   this.element.classList.toggle('has-cursor', false);
175   this.inputElement.tabIndex = '-1';
176   this.autocompleteList.detach();
177 };
178
179 /**
180  * Handles a keydown event of the search box.
181  * @private
182  */
183 SearchBox.prototype.onKeyDown_ = function() {
184   // Handle only Esc key now.
185   if (event.keyCode != 27 || this.inputElement.value)
186     return;
187   this.inputElement.blur();
188 };
189
190 /**
191  * Handles a click event of the search icon.
192  * @private
193  */
194 SearchBox.prototype.onIconClick_ = function() {
195   this.inputElement.focus();
196 };
197
198 /**
199  * Handles a dragenter event and refuses a drag source of files.
200  * @param {DragEvent} event The dragenter event.
201  * @private
202  */
203 SearchBox.prototype.onDragEnter_ = function(event) {
204   // For normal elements, they does not accept drag drop by default, and accept
205   // it by using event.preventDefault. But input elements accept drag drop
206   // by default. So disalbe the input element here to prohibit drag drop.
207   if (event.dataTransfer.types.indexOf('text/plain') === -1)
208     this.inputElement.style.pointerEvents = 'none';
209 };
210
211 /**
212  * Handles a dragend event.
213  * @private
214  */
215 SearchBox.prototype.onDragEnd_ = function() {
216   this.inputElement.style.pointerEvents = '';
217 };
218
219 /**
220  * Updates styles of the search box.
221  * @private
222  */
223 SearchBox.prototype.updateStyles_ = function() {
224   this.element.classList.toggle('has-text',
225                                  !!this.inputElement.value);
226   var width = this.textMeasure_.getWidth(this.inputElement.value) +
227       16 /* Extra space to allow leeway. */;
228   this.inputElement.style.width = width + 'px';
229 };