|
1 /*! |
|
2 \file suggests.js This module contains the Suggests class. |
|
3 */ |
|
4 |
|
5 /*! |
|
6 Class to handle displaying URL suggestions from history and bookmarks. |
|
7 */ |
1 function Suggests() |
8 function Suggests() |
2 { |
9 { |
3 // attach internal funcs |
10 // "Private" member variables |
4 this.write = writeSuggests; |
11 var suggestsXOffset = 20; |
5 |
12 var inputTimeoutId = null; |
6 // do setup |
13 var inputTimeoutDelay = _getTimeoutDelaySetting(); |
7 this.write(); |
14 var maxHeight = 0; // maximum height of suggest list |
8 |
15 var urlSearchHeight = 0; |
9 this.showSuggests = function() { |
16 |
10 window.chrome.alert("showSuggests"); |
17 // "Private" methods |
11 //window.snippets.updateGeometry(); |
18 |
12 window.snippets.SuggestsId.repaint(); |
19 //! Calculates the maximum height for the suggest list. |
13 |
20 //! If not all suggest items can fit in list, only half an item should be |
14 var curPos = window.snippets.SuggestsId.getPosition(); |
21 //! visible the end when scrolled to the top. This is to indicate more items. |
15 window.chrome.alert(curPos.x); |
22 function _setMaxHeight() |
16 if (curPos.y == 0) |
23 { |
17 window.snippets.SuggestsId.setPosition(5,68); |
24 // Calculate height of available space for suggest list. |
18 window.snippets.SuggestsId.show(); |
25 var statusbarSz = snippets.StatusBarChromeId.getGeometry(); |
19 window.snippets.SuggestsId.zValue = 10; |
26 var urlSearchSz = snippets.UrlSearchChromeId.getGeometry(); |
20 } |
27 var toolbarSz = snippets.WebViewToolbarId.getGeometry(); |
21 |
28 // leave some space between suggest and toolbar (~10% of display height) |
22 this.hideSuggests = function() { |
29 var bufferHeight = Math.ceil(chrome.displaySize.height / 10); |
23 window.snippets.SuggestsId.hide(); |
30 var availableHeight = chrome.displaySize.height - |
24 } |
31 (statusbarSz.height + urlSearchSz.height + toolbarSz.height + bufferHeight); |
25 |
32 // Calculate number of elements that can fit in available space. |
26 this.setWidth = function(width) { |
33 var elementHeight = 70; // set in suggests.css |
27 document.getElementById("SuggestsId").style.width = width; |
34 var numElements = Math.floor(availableHeight / elementHeight); |
28 //window.chrome.alert("set width:" + document.getElementById("SuggestsId").offsetWidth); |
35 |
29 } |
36 // in order to make room for 1/2 entry at end of list we may |
30 |
37 // need to sacrifice 1 full element. |
31 this.setHeight = function(height) { |
38 if ((availableHeight % elementHeight) < (elementHeight / 2)) { |
32 document.getElementById("SuggestsId").style.height = height; |
39 numElements -= 1; |
33 //window.chrome.alert("set height:" + document.getElementById("SuggestsId").offsetHeight); |
40 } |
34 } |
41 numElements += 0.5; // half of final visible entry |
35 |
42 // max suggest list height in pixels |
36 this.removeAllItems = function() { |
43 maxHeight = Math.floor(numElements * elementHeight); |
37 var parentList = document.getElementById("SuggestsUListId"); |
44 } |
38 while (parentList.childNodes[0]) { |
45 |
39 parentList.removeChild(parentList.childNodes[0]); |
46 //! Temporary substitute for settings function to get the delay for |
40 } |
47 //! displaying the URL suggests list. |
41 this.setHeight(0); |
48 function _getTimeoutDelaySetting() |
42 } |
49 { |
43 |
50 // no setting stored for this currently |
44 this.addItem = function(str) { |
51 return (1000); // 1 second |
45 this.setHeight(document.getElementById("SuggestsId").offsetHeight + 26); // FIXME 26 is the row height |
52 } |
46 var parentList = document.getElementById("SuggestsUListId"); |
53 |
47 var item = document.createElement("li"); |
54 //! Displays and updates suggest list. |
48 item.innerHTML = str; |
55 function _showSuggests() |
49 item.onclick=function() { window.chrome.alert(item.innerHTML + " is selected."); window.snippets.SuggestsId.hide();} |
56 { |
50 item.onmouseover=function() { item.style.backgroundColor = 'Aquamarine'; } |
57 // make sure the input is the latest |
51 item.onmouseout=function() { item.style.backgroundColor = ''; } |
58 var input = window.snippets.UrlSearchChromeId.url; |
52 parentList.appendChild(item); |
59 |
|
60 // only display suggestions if there is input |
|
61 if (input.length != 0) { |
|
62 _updateSuggestList(input); |
|
63 this.updateSuggestsSize(); |
|
64 |
|
65 if (!snippets.SuggestsChromeId.visible |
|
66 && (pageController.loadState == Suggests.GotoModeEditing)) { |
|
67 window.scrollTo(0, 0); |
|
68 // Disable the content view, leave the URL serach bar and status bar enabled. |
|
69 views.WebView.enabled = false; |
|
70 views.WebView.freeze(); |
|
71 snippets.SuggestsChromeId.show(false); |
|
72 } |
|
73 } else { |
|
74 // no user input so hide suggestions |
|
75 _hideSuggests(); |
|
76 } |
|
77 } |
|
78 |
|
79 //! Updates the suggestion list based on the specified input. |
|
80 /*! |
|
81 \param input the current URL box text |
|
82 */ |
|
83 function _updateSuggestList(input) |
|
84 { |
|
85 var recenturl; |
|
86 var recenttitle = window.localeDelegate.translateText( |
|
87 "txt_browser_chrome_suggests_search_for"); |
|
88 var snippetId = document.getElementById('SuggestsId'); |
|
89 var suggests = window.pageController.fetchSuggestions(input); |
|
90 var suggestUL = document.createElement('ul'); |
|
91 var suggestLI = document.createElement('li'); |
|
92 var pattern = new RegExp(input, "ig"); |
|
93 |
|
94 snippetId.innerHTML = ""; // clear previous results |
|
95 suggestUL.id = 'suggestUlId'; |
|
96 suggestLI.id = "searchLiId"; |
|
97 |
|
98 // always provide an option to search for user entry |
|
99 recenttitle = recenttitle.replace(/%1/, "<b>" + input + "</b>"); |
|
100 |
|
101 suggestLI.innerHTML = '<a href="#" onclick="searchSuggests.searchUrlValue(\''+input+'\');'+ |
|
102 'return false;">'+ |
|
103 '<div class="SuggestElement">'+'<span class="aTitle">'+recenttitle+'</span>'+'</div></a>'; |
|
104 suggestUL.appendChild(suggestLI); |
|
105 |
|
106 // add each search suggestion to unordered list |
|
107 for (i=0; i < suggests.length; i++) { |
|
108 recenturl = suggests[i].url; |
|
109 recenttitle = suggests[i].title; |
|
110 suggestLI = document.createElement('li'); |
|
111 suggestLI.id = "suggestsLiId"; |
|
112 |
|
113 // bold search text |
|
114 recenttitle = recenttitle.replace(pattern, "<b>$&</b>"); |
|
115 recenturl = recenturl.replace(pattern, "<b>$&</b>"); |
|
116 |
|
117 suggestLI.innerHTML = '<a href="#" onclick="searchSuggests.gotoUrl(\''+suggests[i].url+'\');' + |
|
118 ' return false;">'+ |
|
119 '<div class="SuggestElement">'+ |
|
120 '<span class="aTitle">'+recenttitle+'</span><br/>'+ |
|
121 '<span class="aUrl">'+recenturl+'</span></div></a>'; |
|
122 suggestUL.appendChild(suggestLI); |
|
123 } |
|
124 |
|
125 snippetId.appendChild(suggestUL); |
|
126 } |
|
127 |
|
128 //! Hides suggests list and support items. |
|
129 function _hideSuggests() |
|
130 { |
|
131 clearTimeout(inputTimeoutId); |
|
132 window.snippets.SuggestsChromeId.hide(false); |
|
133 views.WebView.enabled = true; |
|
134 views.WebView.unfreeze(); |
|
135 } |
|
136 |
|
137 // Public Functions |
|
138 |
|
139 //! Handler for onload javascript event. |
|
140 this.loadComplete = function() |
|
141 { |
|
142 var urlSearchSz = snippets.UrlSearchChromeId.getGeometry(); |
|
143 |
|
144 urlSearchHeight = urlSearchSz.height; |
|
145 snippets.SuggestsChromeId.anchorTo("UrlSearchChromeId", suggestsXOffset, urlSearchHeight); |
|
146 snippets.SuggestsChromeId.zValue = 10; |
|
147 |
|
148 _setMaxHeight(); // calculate max suggest list height |
|
149 |
|
150 // hide suggests on external mouse events |
|
151 snippets.SuggestsChromeId.externalMouseEvent.connect(this.handleExternalMouseEvent); |
|
152 // need to resize suggest page snippet on geometry change |
|
153 chrome.prepareForGeometryChange.connect(createDelegate(this, this.handleGeometryChange)); |
|
154 } |
|
155 |
|
156 //! Updates the size of the suggests window depending on the size of the |
|
157 //! main DIV -- which changes as the number of items changes. |
|
158 this.updateSuggestsSize = function() |
|
159 { |
|
160 if (snippets.SuggestsChromeId != undefined) { |
|
161 var totalW = chrome.displaySize.width; |
|
162 var divHeight = document.getElementById("SuggestsId").clientHeight + 2; |
|
163 var displayHeight = Math.min(maxHeight, divHeight); |
|
164 var displayWidth = totalW - (2 * suggestsXOffset); |
|
165 |
|
166 // reset snippet height |
|
167 snippets.SuggestsChromeId.setSize(displayWidth, displayHeight); |
|
168 } |
|
169 } |
|
170 |
|
171 //! Handles the geometry change signal. Need to re-calculate max height |
|
172 //! and then update suggest page height. |
|
173 this.handleGeometryChange = function() |
|
174 { |
|
175 _setMaxHeight(); // max height is based on display height |
|
176 this.updateSuggestsSize(); |
|
177 } |
|
178 |
|
179 //! Loads google search page for search string. |
|
180 /*! |
|
181 \param input value to search for |
|
182 */ |
|
183 this.searchUrlValue = function(input) |
|
184 { |
|
185 var searchurl = window.pageController.searchUrl(input); |
|
186 |
|
187 _hideSuggests(); |
|
188 |
|
189 window.pageController.currentLoad(searchurl); |
|
190 window.pageController.urlTextChanged(searchurl); |
|
191 } |
|
192 |
|
193 //! Hides suggests list and loads specified page. |
|
194 /*! |
|
195 \param url address of page to load |
|
196 */ |
|
197 this.gotoUrl = function(url) |
|
198 { |
|
199 _hideSuggests(); |
|
200 url = window.pageController.guessUrlFromString(url); |
|
201 window.pageController.currentLoad(url); |
|
202 window.pageController.urlTextChanged(url); |
|
203 } |
|
204 |
|
205 //! Handles external mouse events - dismisses suggests list. |
|
206 /*! |
|
207 \param type the type of event |
|
208 \param name the name of event |
|
209 \param description event description |
|
210 */ |
|
211 this.handleExternalMouseEvent = function(type, name, description) |
|
212 { |
|
213 if (name == "MouseClick") { |
|
214 _hideSuggests(); |
|
215 } |
|
216 } |
|
217 |
|
218 //! Updates the user input for suggestion list. |
|
219 /*! |
|
220 \param input the current user input |
|
221 */ |
|
222 this.updateUserInput = function() |
|
223 { |
|
224 // user still editing URL - don't show/update suggests yet |
|
225 clearTimeout(inputTimeoutId); |
|
226 inputTimeoutId = setTimeout(_showSuggests.bind(this), inputTimeoutDelay); |
|
227 } |
|
228 |
|
229 //! Called when load state changes. Suggests should only be called when |
|
230 //! the load state is editing. |
|
231 this.updateLoadState = function() |
|
232 { |
|
233 if (pageController.loadState != Suggests.GotoModeEditing) { |
|
234 // loading or reloadable - suggests not ok |
|
235 _hideSuggests(); // ensure suggests are hidden |
|
236 } |
|
237 } |
|
238 |
|
239 //! Called when URL search bar looses focus. The external mouse event |
|
240 //! handler deals with most cases where the suggestion list should be |
|
241 //! dismissed but we don't get those events when the list isn't visible |
|
242 //! so this handler is needed to cancel the timer in those cases. |
|
243 this.urlSearchLostFocus = function() |
|
244 { |
|
245 // if visible user may be scrolling suggestion page so ignore focus change |
|
246 if (!snippets.SuggestsChromeId.visible) { |
|
247 // prevent suggestion list from being displayed until URL edited again |
|
248 clearTimeout(inputTimeoutId); |
|
249 } |
|
250 } |
|
251 |
|
252 //! Sets the user input URL suggest delay. |
|
253 /*! |
|
254 \param to the new delay time. |
|
255 */ |
|
256 this.setSuggestTimeout = function(to) |
|
257 { |
|
258 inputTimeoutDelay = to; |
53 } |
259 } |
54 } |
260 } |
55 |
261 |
56 // "Private" methods |
262 // we don't have access to WRT::LoadController::GotoModeEditing |
57 function writeSuggests() { |
263 Suggests.GotoModeEditing = 1; |
58 var html = |
|
59 '<div class="suggestsBox">' + |
|
60 '<div class="suggestBoxBody">' + |
|
61 '<div id="SuggestsListId" class="show">' + |
|
62 '<ul id="SuggestsUListId">' + |
|
63 '</ul>' + |
|
64 '</div>' + |
|
65 '</div>' + |
|
66 '</div>'; |
|
67 document.write(html); |
|
68 } |
|
69 |
|