1 // Copyright (c) 2011 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 cr.define('options', function() { 6 const OptionsPage = options.OptionsPage; 7 const ArrayDataModel = cr.ui.ArrayDataModel; 8 9 // 10 // BrowserOptions class 11 // Encapsulated handling of browser options page. 12 // 13 function BrowserOptions() { 14 OptionsPage.call(this, 'browser', 15 templateData.browserPageTabTitle, 16 'browserPage'); 17 } 18 19 cr.addSingletonGetter(BrowserOptions); 20 21 BrowserOptions.prototype = { 22 // Inherit BrowserOptions from OptionsPage. 23 __proto__: options.OptionsPage.prototype, 24 25 startup_pages_pref_: { 26 'name': 'session.urls_to_restore_on_startup', 27 'managed': false 28 }, 29 30 homepage_pref_: { 31 'name': 'homepage', 32 'value': '', 33 'managed': false 34 }, 35 36 homepage_is_newtabpage_pref_: { 37 'name': 'homepage_is_newtabpage', 38 'value': true, 39 'managed': false 40 }, 41 42 /** 43 * At autocomplete list that can be attached to a text field during editing. 44 * @type {HTMLElement} 45 * @private 46 */ 47 autocompleteList_: null, 48 49 // The cached value of the instant.confirm_dialog_shown preference. 50 instantConfirmDialogShown_: false, 51 52 /** 53 * Initialize BrowserOptions page. 54 */ 55 initializePage: function() { 56 // Call base class implementation to start preference initialization. 57 OptionsPage.prototype.initializePage.call(this); 58 59 // Wire up controls. 60 $('startupUseCurrentButton').onclick = function(event) { 61 chrome.send('setStartupPagesToCurrentPages'); 62 }; 63 $('toolbarShowBookmarksBar').onchange = function() { 64 chrome.send('toggleShowBookmarksBar'); 65 }; 66 $('defaultSearchManageEnginesButton').onclick = function(event) { 67 OptionsPage.navigateToPage('searchEngines'); 68 chrome.send('coreOptionsUserMetricsAction', 69 ['Options_ManageSearchEngines']); 70 }; 71 $('defaultSearchEngine').onchange = this.setDefaultSearchEngine_; 72 73 var self = this; 74 $('instantEnableCheckbox').onclick = function(event) { 75 if (this.checked && !self.instantConfirmDialogShown_) { 76 // Leave disabled for now. The PrefCheckbox handler already set it to 77 // true so undo that. 78 Preferences.setBooleanPref(this.pref, false, this.metric); 79 OptionsPage.navigateToPage('instantConfirm'); 80 } 81 }; 82 83 Preferences.getInstance().addEventListener('instant.confirm_dialog_shown', 84 this.onInstantConfirmDialogShownChanged_.bind(this)); 85 86 var homepageField = $('homepageURL'); 87 $('homepageUseNTPButton').onchange = 88 this.handleHomepageUseNTPButtonChange_.bind(this); 89 $('homepageUseURLButton').onchange = 90 this.handleHomepageUseURLButtonChange_.bind(this); 91 var homepageChangeHandler = this.handleHomepageURLChange_.bind(this); 92 homepageField.addEventListener('change', homepageChangeHandler); 93 homepageField.addEventListener('input', homepageChangeHandler); 94 homepageField.addEventListener('focus', function(event) { 95 self.autocompleteList_.attachToInput(homepageField); 96 }); 97 homepageField.addEventListener('blur', function(event) { 98 self.autocompleteList_.detach(); 99 }); 100 homepageField.addEventListener('keydown', function(event) { 101 // Remove focus when the user hits enter since people expect feedback 102 // indicating that they are done editing. 103 if (event.keyIdentifier == 'Enter') 104 homepageField.blur(); 105 }); 106 107 // Ensure that changes are committed when closing the page. 108 window.addEventListener('unload', function() { 109 if (document.activeElement == homepageField) 110 homepageField.blur(); 111 }); 112 113 if (!cr.isChromeOS) { 114 $('defaultBrowserUseAsDefaultButton').onclick = function(event) { 115 chrome.send('becomeDefaultBrowser'); 116 }; 117 } 118 119 var startupPagesList = $('startupPagesList'); 120 options.browser_options.StartupPageList.decorate(startupPagesList); 121 startupPagesList.autoExpands = true; 122 123 // Check if we are in the guest mode. 124 if (cr.commandLine.options['--bwsi']) { 125 // Hide the startup section. 126 $('startupSection').classList.add('hidden'); 127 } else { 128 // Initialize control enabled states. 129 Preferences.getInstance().addEventListener('session.restore_on_startup', 130 this.updateCustomStartupPageControlStates_.bind(this)); 131 Preferences.getInstance().addEventListener( 132 this.startup_pages_pref_.name, 133 this.handleStartupPageListChange_.bind(this)); 134 Preferences.getInstance().addEventListener( 135 this.homepage_pref_.name, 136 this.handleHomepageChange_.bind(this)); 137 Preferences.getInstance().addEventListener( 138 this.homepage_is_newtabpage_pref_.name, 139 this.handleHomepageIsNewTabPageChange_.bind(this)); 140 141 this.updateCustomStartupPageControlStates_(); 142 } 143 144 var suggestionList = new options.AutocompleteList(); 145 suggestionList.autoExpands = true; 146 suggestionList.suggestionUpdateRequestCallback = 147 this.requestAutocompleteSuggestions_.bind(this); 148 $('main-content').appendChild(suggestionList); 149 this.autocompleteList_ = suggestionList; 150 startupPagesList.autocompleteList = suggestionList; 151 }, 152 153 /** 154 * Called when the value of the instant.confirm_dialog_shown preference 155 * changes. Cache this value. 156 * @param {Event} event Change event. 157 * @private 158 */ 159 onInstantConfirmDialogShownChanged_: function(event) { 160 this.instantConfirmDialogShown_ = event.value['value']; 161 }, 162 163 /** 164 * Update the Default Browsers section based on the current state. 165 * @param {string} statusString Description of the current default state. 166 * @param {boolean} isDefault Whether or not the browser is currently 167 * default. 168 * @param {boolean} canBeDefault Whether or not the browser can be default. 169 * @private 170 */ 171 updateDefaultBrowserState_: function(statusString, isDefault, 172 canBeDefault) { 173 var label = $('defaultBrowserState'); 174 label.textContent = statusString; 175 176 $('defaultBrowserUseAsDefaultButton').disabled = !canBeDefault || 177 isDefault; 178 }, 179 180 /** 181 * Clears the search engine popup. 182 * @private 183 */ 184 clearSearchEngines_: function() { 185 $('defaultSearchEngine').textContent = ''; 186 }, 187 188 /** 189 * Updates the search engine popup with the given entries. 190 * @param {Array} engines List of available search engines. 191 * @param {number} defaultValue The value of the current default engine. 192 */ 193 updateSearchEngines_: function(engines, defaultValue) { 194 this.clearSearchEngines_(); 195 engineSelect = $('defaultSearchEngine'); 196 engineCount = engines.length; 197 var defaultIndex = -1; 198 for (var i = 0; i < engineCount; i++) { 199 var engine = engines[i]; 200 var option = new Option(engine['name'], engine['index']); 201 if (defaultValue == option.value) 202 defaultIndex = i; 203 engineSelect.appendChild(option); 204 } 205 if (defaultIndex >= 0) 206 engineSelect.selectedIndex = defaultIndex; 207 }, 208 209 /** 210 * Returns true if the custom startup page control block should 211 * be enabled. 212 * @returns {boolean} Whether the startup page controls should be 213 * enabled. 214 */ 215 shouldEnableCustomStartupPageControls: function(pages) { 216 return $('startupShowPagesButton').checked && 217 !this.startup_pages_pref_.managed; 218 }, 219 220 /** 221 * Updates the startup pages list with the given entries. 222 * @param {Array} pages List of startup pages. 223 * @private 224 */ 225 updateStartupPages_: function(pages) { 226 var model = new ArrayDataModel(pages); 227 // Add a "new page" row. 228 model.push({ 229 'modelIndex': '-1' 230 }); 231 $('startupPagesList').dataModel = model; 232 }, 233 234 /** 235 * Handles change events of the radio button 'homepageUseURLButton'. 236 * @param {event} change event. 237 * @private 238 */ 239 handleHomepageUseURLButtonChange_: function(event) { 240 Preferences.setBooleanPref(this.homepage_is_newtabpage_pref_.name, false); 241 }, 242 243 /** 244 * Handles change events of the radio button 'homepageUseNTPButton'. 245 * @param {event} change event. 246 * @private 247 */ 248 handleHomepageUseNTPButtonChange_: function(event) { 249 Preferences.setBooleanPref(this.homepage_is_newtabpage_pref_.name, true); 250 }, 251 252 /** 253 * Handles input and change events of the text field 'homepageURL'. 254 * @param {event} input/change event. 255 * @private 256 */ 257 handleHomepageURLChange_: function(event) { 258 var homepageField = $('homepageURL'); 259 var doFixup = event.type == 'change' ? '1' : '0'; 260 chrome.send('setHomePage', [homepageField.value, doFixup]); 261 }, 262 263 /** 264 * Handle change events of the preference 'homepage'. 265 * @param {event} preference changed event. 266 * @private 267 */ 268 handleHomepageChange_: function(event) { 269 this.homepage_pref_.value = event.value['value']; 270 this.homepage_pref_.managed = event.value['managed']; 271 if (this.isHomepageURLNewTabPageURL_() && !this.homepage_pref_.managed && 272 !this.homepage_is_newtabpage_pref_.managed) { 273 var useNewTabPage = this.isHomepageIsNewTabPageChoiceSelected_(); 274 Preferences.setStringPref(this.homepage_pref_.name, '') 275 Preferences.setBooleanPref(this.homepage_is_newtabpage_pref_.name, 276 useNewTabPage) 277 } 278 this.updateHomepageControlStates_(); 279 }, 280 281 /** 282 * Handle change events of the preference homepage_is_newtabpage. 283 * @param {event} preference changed event. 284 * @private 285 */ 286 handleHomepageIsNewTabPageChange_: function(event) { 287 this.homepage_is_newtabpage_pref_.value = event.value['value']; 288 this.homepage_is_newtabpage_pref_.managed = event.value['managed']; 289 this.updateHomepageControlStates_(); 290 }, 291 292 /** 293 * Update homepage preference UI controls. Here's a table describing the 294 * desired characteristics of the homepage choice radio value, its enabled 295 * state and the URL field enabled state. They depend on the values of the 296 * managed bits for homepage (m_hp) and homepageIsNewTabPage (m_ntp) 297 * preferences, as well as the value of the homepageIsNewTabPage preference 298 * (ntp) and whether the homepage preference is equal to the new tab page 299 * URL (hpisntp). 300 * 301 * m_hp m_ntp ntp hpisntp| choice value| choice enabled| URL field enabled 302 * ------------------------------------------------------------------------ 303 * 0 0 0 0 | homepage | 1 | 1 304 * 0 0 0 1 | new tab page| 1 | 0 305 * 0 0 1 0 | new tab page| 1 | 0 306 * 0 0 1 1 | new tab page| 1 | 0 307 * 0 1 0 0 | homepage | 0 | 1 308 * 0 1 0 1 | homepage | 0 | 1 309 * 0 1 1 0 | new tab page| 0 | 0 310 * 0 1 1 1 | new tab page| 0 | 0 311 * 1 0 0 0 | homepage | 1 | 0 312 * 1 0 0 1 | new tab page| 0 | 0 313 * 1 0 1 0 | new tab page| 1 | 0 314 * 1 0 1 1 | new tab page| 0 | 0 315 * 1 1 0 0 | homepage | 0 | 0 316 * 1 1 0 1 | new tab page| 0 | 0 317 * 1 1 1 0 | new tab page| 0 | 0 318 * 1 1 1 1 | new tab page| 0 | 0 319 * 320 * thus, we have: 321 * 322 * choice value is new tab page === ntp || (hpisntp && (m_hp || !m_ntp)) 323 * choice enabled === !m_ntp && !(m_hp && hpisntp) 324 * URL field enabled === !ntp && !mhp && !(hpisntp && !m_ntp) 325 * 326 * which also make sense if you think about them. 327 * @private 328 */ 329 updateHomepageControlStates_: function() { 330 var homepageField = $('homepageURL'); 331 homepageField.disabled = !this.isHomepageURLFieldEnabled_(); 332 if (homepageField.value != this.homepage_pref_.value) 333 homepageField.value = this.homepage_pref_.value; 334 homepageField.style.backgroundImage = url('chrome://favicon/' + 335 this.homepage_pref_.value); 336 var disableChoice = !this.isHomepageChoiceEnabled_(); 337 $('homepageUseURLButton').disabled = disableChoice; 338 $('homepageUseNTPButton').disabled = disableChoice; 339 var useNewTabPage = this.isHomepageIsNewTabPageChoiceSelected_(); 340 $('homepageUseNTPButton').checked = useNewTabPage; 341 $('homepageUseURLButton').checked = !useNewTabPage; 342 }, 343 344 /** 345 * Tests whether the value of the 'homepage' preference equls the new tab 346 * page url (chrome://newtab). 347 * @returns {boolean} True if the 'homepage' value equals the new tab page 348 * url. 349 * @private 350 */ 351 isHomepageURLNewTabPageURL_ : function() { 352 return (this.homepage_pref_.value.toLowerCase() == 'chrome://newtab'); 353 }, 354 355 /** 356 * Tests whether the Homepage choice "Use New Tab Page" is selected. 357 * @returns {boolean} True if "Use New Tab Page" is selected. 358 * @private 359 */ 360 isHomepageIsNewTabPageChoiceSelected_: function() { 361 return (this.homepage_is_newtabpage_pref_.value || 362 (this.isHomepageURLNewTabPageURL_() && 363 (this.homepage_pref_.managed || 364 !this.homepage_is_newtabpage_pref_.managed))); 365 }, 366 367 /** 368 * Tests whether the home page choice controls are enabled. 369 * @returns {boolean} True if the home page choice controls are enabled. 370 * @private 371 */ 372 isHomepageChoiceEnabled_: function() { 373 return (!this.homepage_is_newtabpage_pref_.managed && 374 !(this.homepage_pref_.managed && 375 this.isHomepageURLNewTabPageURL_())); 376 }, 377 378 /** 379 * Checks whether the home page field should be enabled. 380 * @returns {boolean} True if the home page field should be enabled. 381 * @private 382 */ 383 isHomepageURLFieldEnabled_: function() { 384 return (!this.homepage_is_newtabpage_pref_.value && 385 !this.homepage_pref_.managed && 386 !(this.isHomepageURLNewTabPageURL_() && 387 !this.homepage_is_newtabpage_pref_.managed)); 388 }, 389 390 /** 391 * Sets the enabled state of the custom startup page list controls 392 * based on the current startup radio button selection. 393 * @private 394 */ 395 updateCustomStartupPageControlStates_: function() { 396 var disable = !this.shouldEnableCustomStartupPageControls(); 397 $('startupPagesList').disabled = disable; 398 $('startupUseCurrentButton').disabled = disable; 399 }, 400 401 /** 402 * Handle change events of the preference 403 * 'session.urls_to_restore_on_startup'. 404 * @param {event} preference changed event. 405 * @private 406 */ 407 handleStartupPageListChange_: function(event) { 408 this.startup_pages_pref_.managed = event.value['managed']; 409 this.updateCustomStartupPageControlStates_(); 410 }, 411 412 /** 413 * Set the default search engine based on the popup selection. 414 */ 415 setDefaultSearchEngine_: function() { 416 var engineSelect = $('defaultSearchEngine'); 417 var selectedIndex = engineSelect.selectedIndex; 418 if (selectedIndex >= 0) { 419 var selection = engineSelect.options[selectedIndex]; 420 chrome.send('setDefaultSearchEngine', [String(selection.value)]); 421 } 422 }, 423 424 /** 425 * Sends an asynchronous request for new autocompletion suggestions for the 426 * the given query. When new suggestions are available, the C++ handler will 427 * call updateAutocompleteSuggestions_. 428 * @param {string} query List of autocomplete suggestions. 429 * @private 430 */ 431 requestAutocompleteSuggestions_: function(query) { 432 chrome.send('requestAutocompleteSuggestions', [query]); 433 }, 434 435 /** 436 * Updates the autocomplete suggestion list with the given entries. 437 * @param {Array} pages List of autocomplete suggestions. 438 * @private 439 */ 440 updateAutocompleteSuggestions_: function(suggestions) { 441 var list = this.autocompleteList_; 442 // If the trigger for this update was a value being selected from the 443 // current list, do nothing. 444 if (list.targetInput && list.selectedItem && 445 list.selectedItem['url'] == list.targetInput.value) 446 return; 447 list.suggestions = suggestions; 448 }, 449 }; 450 451 BrowserOptions.updateDefaultBrowserState = function(statusString, isDefault, 452 canBeDefault) { 453 if (!cr.isChromeOS) { 454 BrowserOptions.getInstance().updateDefaultBrowserState_(statusString, 455 isDefault, 456 canBeDefault); 457 } 458 }; 459 460 BrowserOptions.updateSearchEngines = function(engines, defaultValue) { 461 BrowserOptions.getInstance().updateSearchEngines_(engines, defaultValue); 462 }; 463 464 BrowserOptions.updateStartupPages = function(pages) { 465 BrowserOptions.getInstance().updateStartupPages_(pages); 466 }; 467 468 BrowserOptions.updateAutocompleteSuggestions = function(suggestions) { 469 BrowserOptions.getInstance().updateAutocompleteSuggestions_(suggestions); 470 }; 471 472 // Export 473 return { 474 BrowserOptions: BrowserOptions 475 }; 476 477 }); 478