OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 // TODO(kochi): Generalize the notification as a component and put it | |
6 // in js/cr/ui/notification.js . | |
7 | |
8 cr.define('options', function() { | |
9 const OptionsPage = options.OptionsPage; | |
10 const LanguageList = options.LanguageList; | |
11 | |
12 // Some input methods like Chinese Pinyin have config pages. | |
13 // This is the map of the input method names to their config page names. | |
14 const INPUT_METHOD_ID_TO_CONFIG_PAGE_NAME = { | |
15 'mozc': 'languageMozc', | |
16 'mozc-chewing': 'languageChewing', | |
17 'mozc-dv': 'languageMozc', | |
18 'mozc-hangul': 'languageHangul', | |
19 'mozc-jp': 'languageMozc', | |
20 'pinyin': 'languagePinyin', | |
21 'pinyin-dv': 'languagePinyin', | |
22 }; | |
23 | |
24 ///////////////////////////////////////////////////////////////////////////// | |
25 // LanguageOptions class: | |
26 | |
27 /** | |
28 * Encapsulated handling of ChromeOS language options page. | |
29 * @constructor | |
30 */ | |
31 function LanguageOptions(model) { | |
32 OptionsPage.call(this, 'languages', templateData.languagePageTabTitle, | |
33 'languagePage'); | |
34 } | |
35 | |
36 cr.addSingletonGetter(LanguageOptions); | |
37 | |
38 // Inherit LanguageOptions from OptionsPage. | |
39 LanguageOptions.prototype = { | |
40 __proto__: OptionsPage.prototype, | |
41 | |
42 /** | |
43 * Initializes LanguageOptions page. | |
44 * Calls base class implementation to starts preference initialization. | |
45 */ | |
46 initializePage: function() { | |
47 OptionsPage.prototype.initializePage.call(this); | |
48 | |
49 var languageOptionsList = $('language-options-list'); | |
50 LanguageList.decorate(languageOptionsList); | |
51 | |
52 languageOptionsList.addEventListener('change', | |
53 this.handleLanguageOptionsListChange_.bind(this)); | |
54 languageOptionsList.addEventListener('save', | |
55 this.handleLanguageOptionsListSave_.bind(this)); | |
56 | |
57 this.addEventListener('visibleChange', | |
58 this.handleVisibleChange_.bind(this)); | |
59 | |
60 if (cr.isChromeOS) { | |
61 this.initializeInputMethodList_(); | |
62 this.initializeLanguageCodeToInputMethodIdsMap_(); | |
63 } | |
64 Preferences.getInstance().addEventListener(this.spellCheckDictionaryPref, | |
65 this.handleSpellCheckDictionaryPrefChange_.bind(this)); | |
66 | |
67 // Set up add button. | |
68 $('language-options-add-button').onclick = function(e) { | |
69 // Add the language without showing the overlay if it's specified in | |
70 // the URL hash (ex. lang_add=ja). Used for automated testing. | |
71 var match = document.location.hash.match(/\blang_add=([\w-]+)/); | |
72 if (match) { | |
73 var addLanguageCode = match[1]; | |
74 $('language-options-list').addLanguage(addLanguageCode); | |
75 } else { | |
76 OptionsPage.navigateToPage('addLanguage'); | |
77 } | |
78 }; | |
79 | |
80 if (cr.isChromeOS) { | |
81 // Listen to user clicks on the add language list. | |
82 var addLanguageList = $('add-language-overlay-language-list'); | |
83 addLanguageList.addEventListener('click', | |
84 this.handleAddLanguageListClick_.bind(this)); | |
85 } else { | |
86 // Listen to add language dialog ok button. | |
87 var addLanguageOkButton = $('add-language-overlay-ok-button'); | |
88 addLanguageOkButton.addEventListener('click', | |
89 this.handleAddLanguageOkButtonClick_.bind(this)); | |
90 | |
91 // Show experimental features if enabled. | |
92 if (templateData.experimentalSpellCheckFeatures == 'true') | |
93 $('auto-spell-correction-option').hidden = false; | |
94 | |
95 // Handle spell check enable/disable. | |
96 if (!cr.isMac) { | |
97 Preferences.getInstance().addEventListener( | |
98 this.enableSpellCheckPref, | |
99 this.updateEnableSpellCheck_.bind(this)); | |
100 } | |
101 } | |
102 | |
103 // Listen to user clicks on the "Change touch keyboard settings..." | |
104 // button (if it exists). | |
105 var virtualKeyboardButton = $('language-options-virtual-keyboard'); | |
106 if (virtualKeyboardButton) { | |
107 // TODO(yusukes): would be better to hide the button if no virtual | |
108 // keyboard is registered. | |
109 virtualKeyboardButton.onclick = function(e) { | |
110 OptionsPage.navigateToPage('virtualKeyboards'); | |
111 }; | |
112 } | |
113 }, | |
114 | |
115 // The preference is a boolean that enables/disables spell checking. | |
116 enableSpellCheckPref: 'browser.enable_spellchecking', | |
117 // The preference is a CSV string that describes preload engines | |
118 // (i.e. active input methods). | |
119 preloadEnginesPref: 'settings.language.preload_engines', | |
120 // The list of preload engines, like ['mozc', 'pinyin']. | |
121 preloadEngines_: [], | |
122 // The preference is a string that describes the spell check | |
123 // dictionary language, like "en-US". | |
124 spellCheckDictionaryPref: 'spellcheck.dictionary', | |
125 spellCheckDictionary_: "", | |
126 // The map of language code to input method IDs, like: | |
127 // {'ja': ['mozc', 'mozc-jp'], 'zh-CN': ['pinyin'], ...} | |
128 languageCodeToInputMethodIdsMap_: {}, | |
129 | |
130 /** | |
131 * Initializes the input method list. | |
132 */ | |
133 initializeInputMethodList_: function() { | |
134 var inputMethodList = $('language-options-input-method-list'); | |
135 var inputMethodListData = templateData.inputMethodList; | |
136 | |
137 // Add all input methods, but make all of them invisible here. We'll | |
138 // change the visibility in handleLanguageOptionsListChange_() based | |
139 // on the selected language. Note that we only have less than 100 | |
140 // input methods, so creating DOM nodes at once here should be ok. | |
141 for (var i = 0; i < inputMethodListData.length; i++) { | |
142 var inputMethod = inputMethodListData[i]; | |
143 var input = document.createElement('input'); | |
144 input.type = 'checkbox'; | |
145 input.inputMethodId = inputMethod.id; | |
146 // Listen to user clicks. | |
147 input.addEventListener('click', | |
148 this.handleCheckboxClick_.bind(this)); | |
149 var label = document.createElement('label'); | |
150 label.appendChild(input); | |
151 // Adding a space between the checkbox and the text. This is a bit | |
152 // dirty, but we rely on a space character for all other checkboxes. | |
153 label.appendChild(document.createTextNode( | |
154 ' ' + inputMethod.displayName)); | |
155 label.style.display = 'none'; | |
156 label.languageCodeSet = inputMethod.languageCodeSet; | |
157 // Add the configure button if the config page is present for this | |
158 // input method. | |
159 if (inputMethod.id in INPUT_METHOD_ID_TO_CONFIG_PAGE_NAME) { | |
160 var pageName = INPUT_METHOD_ID_TO_CONFIG_PAGE_NAME[inputMethod.id]; | |
161 var button = this.createConfigureInputMethodButton_(inputMethod.id, | |
162 pageName); | |
163 label.appendChild(button); | |
164 } | |
165 | |
166 inputMethodList.appendChild(label); | |
167 } | |
168 // Listen to pref change once the input method list is initialized. | |
169 Preferences.getInstance().addEventListener(this.preloadEnginesPref, | |
170 this.handlePreloadEnginesPrefChange_.bind(this)); | |
171 }, | |
172 | |
173 /** | |
174 * Creates a configure button for the given input method ID. | |
175 * @param {string} inputMethodId Input method ID (ex. "pinyin"). | |
176 * @param {string} pageName Name of the config page (ex. "languagePinyin"). | |
177 * @private | |
178 */ | |
179 createConfigureInputMethodButton_: function(inputMethodId, pageName) { | |
180 var button = document.createElement('button'); | |
181 button.textContent = localStrings.getString('configure'); | |
182 button.onclick = function(e) { | |
183 // Prevent the default action (i.e. changing the checked property | |
184 // of the checkbox). The button click here should not be handled | |
185 // as checkbox click. | |
186 e.preventDefault(); | |
187 chrome.send('inputMethodOptionsOpen', [inputMethodId]); | |
188 OptionsPage.navigateToPage(pageName); | |
189 } | |
190 return button; | |
191 }, | |
192 | |
193 /** | |
194 * Handles OptionsPage's visible property change event. | |
195 * @param {Event} e Property change event. | |
196 * @private | |
197 */ | |
198 handleVisibleChange_: function(e) { | |
199 if (this.visible) { | |
200 $('language-options-list').redraw(); | |
201 chrome.send('languageOptionsOpen'); | |
202 } | |
203 }, | |
204 | |
205 /** | |
206 * Handles languageOptionsList's change event. | |
207 * @param {Event} e Change event. | |
208 * @private | |
209 */ | |
210 handleLanguageOptionsListChange_: function(e) { | |
211 var languageOptionsList = $('language-options-list'); | |
212 var languageCode = languageOptionsList.getSelectedLanguageCode(); | |
213 // Select the language if it's specified in the URL hash (ex. lang=ja). | |
214 // Used for automated testing. | |
215 var match = document.location.hash.match(/\blang=([\w-]+)/); | |
216 if (match) { | |
217 var specifiedLanguageCode = match[1]; | |
218 if (languageOptionsList.selectLanguageByCode(specifiedLanguageCode)) { | |
219 languageCode = specifiedLanguageCode; | |
220 } | |
221 } | |
222 this.updateSelectedLanguageName_(languageCode); | |
223 if (cr.isWindows || cr.isChromeOS) | |
224 this.updateUiLanguageButton_(languageCode); | |
225 if (!cr.isMac) | |
226 this.updateSpellCheckLanguageButton_(languageCode); | |
227 if (cr.isChromeOS) | |
228 this.updateInputMethodList_(languageCode); | |
229 this.updateLanguageListInAddLanguageOverlay_(); | |
230 }, | |
231 | |
232 /** | |
233 * Handles languageOptionsList's save event. | |
234 * @param {Event} e Save event. | |
235 * @private | |
236 */ | |
237 handleLanguageOptionsListSave_: function(e) { | |
238 if (cr.isChromeOS) { | |
239 // Sort the preload engines per the saved languages before save. | |
240 this.preloadEngines_ = this.sortPreloadEngines_(this.preloadEngines_); | |
241 this.savePreloadEnginesPref_(); | |
242 } | |
243 }, | |
244 | |
245 /** | |
246 * Sorts preloadEngines_ by languageOptionsList's order. | |
247 * @param {Array} preloadEngines List of preload engines. | |
248 * @return {Array} Returns sorted preloadEngines. | |
249 * @private | |
250 */ | |
251 sortPreloadEngines_: function(preloadEngines) { | |
252 // For instance, suppose we have two languages and associated input | |
253 // methods: | |
254 // | |
255 // - Korean: hangul | |
256 // - Chinese: pinyin | |
257 // | |
258 // The preloadEngines preference should look like "hangul,pinyin". | |
259 // If the user reverse the order, the preference should be reorderd | |
260 // to "pinyin,hangul". | |
261 var languageOptionsList = $('language-options-list'); | |
262 var languageCodes = languageOptionsList.getLanguageCodes(); | |
263 | |
264 // Convert the list into a dictonary for simpler lookup. | |
265 var preloadEngineSet = {}; | |
266 for (var i = 0; i < preloadEngines.length; i++) { | |
267 preloadEngineSet[preloadEngines[i]] = true; | |
268 } | |
269 | |
270 // Create the new preload engine list per the language codes. | |
271 var newPreloadEngines = []; | |
272 for (var i = 0; i < languageCodes.length; i++) { | |
273 var languageCode = languageCodes[i]; | |
274 var inputMethodIds = this.languageCodeToInputMethodIdsMap_[ | |
275 languageCode]; | |
276 // Check if we have active input methods associated with the language. | |
277 for (var j = 0; j < inputMethodIds.length; j++) { | |
278 var inputMethodId = inputMethodIds[j]; | |
279 if (inputMethodId in preloadEngineSet) { | |
280 // If we have, add it to the new engine list. | |
281 newPreloadEngines.push(inputMethodId); | |
282 // And delete it from the set. This is necessary as one input | |
283 // method can be associated with more than one language thus | |
284 // we should avoid having duplicates in the new list. | |
285 delete preloadEngineSet[inputMethodId]; | |
286 } | |
287 } | |
288 } | |
289 | |
290 return newPreloadEngines; | |
291 }, | |
292 | |
293 /** | |
294 * Initializes the map of language code to input method IDs. | |
295 * @private | |
296 */ | |
297 initializeLanguageCodeToInputMethodIdsMap_: function() { | |
298 var inputMethodList = templateData.inputMethodList; | |
299 for (var i = 0; i < inputMethodList.length; i++) { | |
300 var inputMethod = inputMethodList[i]; | |
301 for (var languageCode in inputMethod.languageCodeSet) { | |
302 if (languageCode in this.languageCodeToInputMethodIdsMap_) { | |
303 this.languageCodeToInputMethodIdsMap_[languageCode].push( | |
304 inputMethod.id); | |
305 } else { | |
306 this.languageCodeToInputMethodIdsMap_[languageCode] = | |
307 [inputMethod.id]; | |
308 } | |
309 } | |
310 } | |
311 }, | |
312 | |
313 /** | |
314 * Updates the currently selected language name. | |
315 * @param {string} languageCode Language code (ex. "fr"). | |
316 * @private | |
317 */ | |
318 updateSelectedLanguageName_: function(languageCode) { | |
319 var languageDisplayName = LanguageList.getDisplayNameFromLanguageCode( | |
320 languageCode); | |
321 var languageNativeDisplayName = | |
322 LanguageList.getNativeDisplayNameFromLanguageCode(languageCode); | |
323 // If the native name is different, add it. | |
324 if (languageDisplayName != languageNativeDisplayName) { | |
325 languageDisplayName += ' - ' + languageNativeDisplayName; | |
326 } | |
327 // Update the currently selected language name. | |
328 var languageName = $('language-options-language-name'); | |
329 if (languageDisplayName) { | |
330 languageName.hidden = false; | |
331 languageName.textContent = languageDisplayName; | |
332 } else { | |
333 languageName.hidden = true; | |
334 } | |
335 }, | |
336 | |
337 /** | |
338 * Updates the UI language button. | |
339 * @param {string} languageCode Language code (ex. "fr"). | |
340 * @private | |
341 */ | |
342 updateUiLanguageButton_: function(languageCode) { | |
343 var uiLanguageButton = $('language-options-ui-language-button'); | |
344 // Check if the language code matches the current UI language. | |
345 if (languageCode == templateData.currentUiLanguageCode) { | |
346 // If it matches, the button just says that the UI language is | |
347 // currently in use. | |
348 uiLanguageButton.textContent = | |
349 localStrings.getString('is_displayed_in_this_language'); | |
350 // Make it look like a text label. | |
351 uiLanguageButton.className = 'text-button'; | |
352 // Remove the event listner. | |
353 uiLanguageButton.onclick = undefined; | |
354 } else if (languageCode in templateData.uiLanguageCodeSet) { | |
355 // If the language is supported as UI language, users can click on | |
356 // the button to change the UI language. | |
357 if (cr.commandLine && cr.commandLine.options['--bwsi']) { | |
358 // In the guest mode for ChromeOS, changing UI language does not make | |
359 // sense because it does not take effect after browser restart. | |
360 uiLanguageButton.hidden = true; | |
361 } else { | |
362 uiLanguageButton.textContent = | |
363 localStrings.getString('display_in_this_language'); | |
364 uiLanguageButton.className = ''; | |
365 // Send the change request to Chrome. | |
366 uiLanguageButton.onclick = function(e) { | |
367 chrome.send('uiLanguageChange', [languageCode]); | |
368 } | |
369 } | |
370 if (cr.isChromeOS) { | |
371 $('language-options-ui-restart-button').onclick = function(e) { | |
372 chrome.send('uiLanguageRestart'); | |
373 } | |
374 } | |
375 } else { | |
376 // If the language is not supported as UI language, the button | |
377 // just says that Chromium OS cannot be displayed in this language. | |
378 uiLanguageButton.textContent = | |
379 localStrings.getString('cannot_be_displayed_in_this_language'); | |
380 uiLanguageButton.className = 'text-button'; | |
381 uiLanguageButton.onclick = undefined; | |
382 } | |
383 uiLanguageButton.style.display = 'block'; | |
384 $('language-options-ui-notification-bar').style.display = 'none'; | |
385 }, | |
386 | |
387 /** | |
388 * Updates the spell check language button. | |
389 * @param {string} languageCode Language code (ex. "fr"). | |
390 * @private | |
391 */ | |
392 updateSpellCheckLanguageButton_: function(languageCode) { | |
393 var display = 'block'; | |
394 var spellCheckLanguageButton = $( | |
395 'language-options-spell-check-language-button'); | |
396 // Check if the language code matches the current spell check language. | |
397 if (languageCode == this.spellCheckDictionary_) { | |
398 // If it matches, the button just says that the spell check language is | |
399 // currently in use. | |
400 spellCheckLanguageButton.textContent = | |
401 localStrings.getString('is_used_for_spell_checking'); | |
402 // Make it look like a text label. | |
403 spellCheckLanguageButton.className = 'text-button'; | |
404 // Remove the event listner. | |
405 spellCheckLanguageButton.onclick = undefined; | |
406 } else if (languageCode in templateData.spellCheckLanguageCodeSet) { | |
407 // If the language is supported as spell check language, users can | |
408 // click on the button to change the spell check language. | |
409 spellCheckLanguageButton.textContent = | |
410 localStrings.getString('use_this_for_spell_checking'); | |
411 spellCheckLanguageButton.className = ''; | |
412 spellCheckLanguageButton.languageCode = languageCode; | |
413 // Add an event listner to the click event. | |
414 spellCheckLanguageButton.addEventListener('click', | |
415 this.handleSpellCheckLanguageButtonClick_.bind(this)); | |
416 } else if (!languageCode) { | |
417 display = 'none'; | |
418 } else { | |
419 // If the language is not supported as spell check language, the | |
420 // button just says that this language cannot be used for spell | |
421 // checking. | |
422 spellCheckLanguageButton.textContent = | |
423 localStrings.getString('cannot_be_used_for_spell_checking'); | |
424 spellCheckLanguageButton.className = 'text-button'; | |
425 spellCheckLanguageButton.onclick = undefined; | |
426 } | |
427 spellCheckLanguageButton.style.display = display; | |
428 $('language-options-ui-notification-bar').style.display = 'none'; | |
429 }, | |
430 | |
431 /** | |
432 * Updates the input method list. | |
433 * @param {string} languageCode Language code (ex. "fr"). | |
434 * @private | |
435 */ | |
436 updateInputMethodList_: function(languageCode) { | |
437 // Give one of the checkboxes or buttons focus, if it's specified in the | |
438 // URL hash (ex. focus=mozc). Used for automated testing. | |
439 var focusInputMethodId = -1; | |
440 var match = document.location.hash.match(/\bfocus=([\w:-]+)\b/); | |
441 if (match) { | |
442 focusInputMethodId = match[1]; | |
443 } | |
444 // Change the visibility of the input method list. Input methods that | |
445 // matches |languageCode| will become visible. | |
446 var inputMethodList = $('language-options-input-method-list'); | |
447 var labels = inputMethodList.querySelectorAll('label'); | |
448 for (var i = 0; i < labels.length; i++) { | |
449 var label = labels[i]; | |
450 if (languageCode in label.languageCodeSet) { | |
451 label.style.display = 'block'; | |
452 var input = label.childNodes[0]; | |
453 // Give it focus if the ID matches. | |
454 if (input.inputMethodId == focusInputMethodId) { | |
455 input.focus(); | |
456 } | |
457 } else { | |
458 label.style.display = 'none'; | |
459 } | |
460 } | |
461 | |
462 if (focusInputMethodId == 'add') { | |
463 $('language-options-add-button').focus(); | |
464 } | |
465 }, | |
466 | |
467 /** | |
468 * Updates the language list in the add language overlay. | |
469 * @param {string} languageCode Language code (ex. "fr"). | |
470 * @private | |
471 */ | |
472 updateLanguageListInAddLanguageOverlay_: function(languageCode) { | |
473 // Change the visibility of the language list in the add language | |
474 // overlay. Languages that are already active will become invisible, | |
475 // so that users don't add the same language twice. | |
476 var languageOptionsList = $('language-options-list'); | |
477 var languageCodes = languageOptionsList.getLanguageCodes(); | |
478 var languageCodeSet = {}; | |
479 for (var i = 0; i < languageCodes.length; i++) { | |
480 languageCodeSet[languageCodes[i]] = true; | |
481 } | |
482 var addLanguageList = $('add-language-overlay-language-list'); | |
483 var lis = addLanguageList.querySelectorAll('li'); | |
484 for (var i = 0; i < lis.length; i++) { | |
485 // The first child button knows the language code. | |
486 var button = lis[i].childNodes[0]; | |
487 if (button.languageCode in languageCodeSet) { | |
488 lis[i].style.display = 'none'; | |
489 } else { | |
490 lis[i].style.display = 'block'; | |
491 } | |
492 } | |
493 }, | |
494 | |
495 /** | |
496 * Handles preloadEnginesPref change. | |
497 * @param {Event} e Change event. | |
498 * @private | |
499 */ | |
500 handlePreloadEnginesPrefChange_: function(e) { | |
501 var value = e.value.value; | |
502 this.preloadEngines_ = this.filterBadPreloadEngines_(value.split(',')); | |
503 this.updateCheckboxesFromPreloadEngines_(); | |
504 $('language-options-list').updateDeletable(); | |
505 }, | |
506 | |
507 /** | |
508 * Handles input method checkbox's click event. | |
509 * @param {Event} e Click event. | |
510 * @private | |
511 */ | |
512 handleCheckboxClick_ : function(e) { | |
513 var checkbox = e.target; | |
514 if (this.preloadEngines_.length == 1 && !checkbox.checked) { | |
515 // Don't allow disabling the last input method. | |
516 this.showNotification_( | |
517 localStrings.getString('please_add_another_input_method'), | |
518 localStrings.getString('ok_button')); | |
519 checkbox.checked = true; | |
520 return; | |
521 } | |
522 if (checkbox.checked) { | |
523 chrome.send('inputMethodEnable', [checkbox.inputMethodId]); | |
524 } else { | |
525 chrome.send('inputMethodDisable', [checkbox.inputMethodId]); | |
526 } | |
527 this.updatePreloadEnginesFromCheckboxes_(); | |
528 this.preloadEngines_ = this.sortPreloadEngines_(this.preloadEngines_); | |
529 this.savePreloadEnginesPref_(); | |
530 }, | |
531 | |
532 /** | |
533 * Handles add language list's click event. | |
534 * @param {Event} e Click event. | |
535 */ | |
536 handleAddLanguageListClick_ : function(e) { | |
537 var languageOptionsList = $('language-options-list'); | |
538 var languageCode = e.target.languageCode; | |
539 // languageCode can be undefined, if click was made on some random | |
540 // place in the overlay, rather than a button. Ignore it. | |
541 if (!languageCode) { | |
542 return; | |
543 } | |
544 languageOptionsList.addLanguage(languageCode); | |
545 var inputMethodIds = this.languageCodeToInputMethodIdsMap_[languageCode]; | |
546 // Enable the first input method for the language added. | |
547 if (inputMethodIds && inputMethodIds[0] && | |
548 // Don't add the input method it's already present. This can | |
549 // happen if the same input method is shared among multiple | |
550 // languages (ex. English US keyboard is used for English US and | |
551 // Filipino). | |
552 this.preloadEngines_.indexOf(inputMethodIds[0]) == -1) { | |
553 this.preloadEngines_.push(inputMethodIds[0]); | |
554 this.updateCheckboxesFromPreloadEngines_(); | |
555 this.savePreloadEnginesPref_(); | |
556 } | |
557 OptionsPage.closeOverlay(); | |
558 }, | |
559 | |
560 /** | |
561 * Handles add language dialog ok button. | |
562 */ | |
563 handleAddLanguageOkButtonClick_ : function() { | |
564 var languagesSelect = $('add-language-overlay-language-list'); | |
565 var selectedIndex = languagesSelect.selectedIndex; | |
566 if (selectedIndex >= 0) { | |
567 var selection = languagesSelect.options[selectedIndex]; | |
568 $('language-options-list').addLanguage(String(selection.value)); | |
569 OptionsPage.closeOverlay(); | |
570 } | |
571 }, | |
572 | |
573 /** | |
574 * Checks if languageCode is deletable or not. | |
575 * @param {String} languageCode the languageCode to check for deletability. | |
576 */ | |
577 languageIsDeletable: function(languageCode) { | |
578 // Don't allow removing the language if it's as UI language. | |
579 if (languageCode == templateData.currentUiLanguageCode) | |
580 return false; | |
581 return (!cr.isChromeOS || | |
582 this.canDeleteLanguage_(languageCode)); | |
583 }, | |
584 | |
585 /** | |
586 * Handles browse.enable_spellchecking change. | |
587 * @param {Event} e Change event. | |
588 * @private | |
589 */ | |
590 updateEnableSpellCheck_: function() { | |
591 var value = !$('enable-spell-check').checked; | |
592 | |
593 $('language-options-spell-check-language-button').disabled = value; | |
594 }, | |
595 | |
596 /** | |
597 * Handles spellCheckDictionaryPref change. | |
598 * @param {Event} e Change event. | |
599 * @private | |
600 */ | |
601 handleSpellCheckDictionaryPrefChange_: function(e) { | |
602 var languageCode = e.value.value | |
603 this.spellCheckDictionary_ = languageCode; | |
604 var languageOptionsList = $('language-options-list'); | |
605 var selectedLanguageCode = languageOptionsList.getSelectedLanguageCode(); | |
606 if (!cr.isMac) | |
607 this.updateSpellCheckLanguageButton_(selectedLanguageCode); | |
608 }, | |
609 | |
610 /** | |
611 * Handles spellCheckLanguageButton click. | |
612 * @param {Event} e Click event. | |
613 * @private | |
614 */ | |
615 handleSpellCheckLanguageButtonClick_: function(e) { | |
616 var languageCode = e.target.languageCode; | |
617 // Save the preference. | |
618 Preferences.setStringPref(this.spellCheckDictionaryPref, | |
619 languageCode); | |
620 chrome.send('spellCheckLanguageChange', [languageCode]); | |
621 }, | |
622 | |
623 /** | |
624 * Checks whether it's possible to remove the language specified by | |
625 * languageCode and returns true if possible. This function returns false | |
626 * if the removal causes the number of preload engines to be zero. | |
627 * | |
628 * @param {string} languageCode Language code (ex. "fr"). | |
629 * @return {boolean} Returns true on success. | |
630 * @private | |
631 */ | |
632 canDeleteLanguage_: function(languageCode) { | |
633 // First create the set of engines to be removed from input methods | |
634 // associated with the language code. | |
635 var enginesToBeRemovedSet = {}; | |
636 var inputMethodIds = this.languageCodeToInputMethodIdsMap_[languageCode]; | |
637 for (var i = 0; i < inputMethodIds.length; i++) { | |
638 enginesToBeRemovedSet[inputMethodIds[i]] = true; | |
639 } | |
640 | |
641 // Then eliminate engines that are also used for other active languages. | |
642 // For instance, if "xkb:us::eng" is used for both English and Filipino. | |
643 var languageCodes = $('language-options-list').getLanguageCodes(); | |
644 for (var i = 0; i < languageCodes.length; i++) { | |
645 // Skip the target language code. | |
646 if (languageCodes[i] == languageCode) { | |
647 continue; | |
648 } | |
649 // Check if input methods used in this language are included in | |
650 // enginesToBeRemovedSet. If so, eliminate these from the set, so | |
651 // we don't remove this time. | |
652 var inputMethodIdsForAnotherLanguage = | |
653 this.languageCodeToInputMethodIdsMap_[languageCodes[i]]; | |
654 for (var j = 0; j < inputMethodIdsForAnotherLanguage.length; j++) { | |
655 var inputMethodId = inputMethodIdsForAnotherLanguage[j]; | |
656 if (inputMethodId in enginesToBeRemovedSet) { | |
657 delete enginesToBeRemovedSet[inputMethodId]; | |
658 } | |
659 } | |
660 } | |
661 | |
662 // Update the preload engine list with the to-be-removed set. | |
663 var newPreloadEngines = []; | |
664 for (var i = 0; i < this.preloadEngines_.length; i++) { | |
665 if (!(this.preloadEngines_[i] in enginesToBeRemovedSet)) { | |
666 newPreloadEngines.push(this.preloadEngines_[i]); | |
667 } | |
668 } | |
669 // Don't allow this operation if it causes the number of preload | |
670 // engines to be zero. | |
671 return (newPreloadEngines.length > 0); | |
672 }, | |
673 | |
674 /** | |
675 * Saves the preload engines preference. | |
676 * @private | |
677 */ | |
678 savePreloadEnginesPref_: function() { | |
679 Preferences.setStringPref(this.preloadEnginesPref, | |
680 this.preloadEngines_.join(',')); | |
681 }, | |
682 | |
683 /** | |
684 * Updates the checkboxes in the input method list from the preload | |
685 * engines preference. | |
686 * @private | |
687 */ | |
688 updateCheckboxesFromPreloadEngines_: function() { | |
689 // Convert the list into a dictonary for simpler lookup. | |
690 var dictionary = {}; | |
691 for (var i = 0; i < this.preloadEngines_.length; i++) { | |
692 dictionary[this.preloadEngines_[i]] = true; | |
693 } | |
694 | |
695 var inputMethodList = $('language-options-input-method-list'); | |
696 var checkboxes = inputMethodList.querySelectorAll('input'); | |
697 for (var i = 0; i < checkboxes.length; i++) { | |
698 checkboxes[i].checked = (checkboxes[i].inputMethodId in dictionary); | |
699 } | |
700 }, | |
701 | |
702 /** | |
703 * Updates the preload engines preference from the checkboxes in the | |
704 * input method list. | |
705 * @private | |
706 */ | |
707 updatePreloadEnginesFromCheckboxes_: function() { | |
708 this.preloadEngines_ = []; | |
709 var inputMethodList = $('language-options-input-method-list'); | |
710 var checkboxes = inputMethodList.querySelectorAll('input'); | |
711 for (var i = 0; i < checkboxes.length; i++) { | |
712 if (checkboxes[i].checked) { | |
713 this.preloadEngines_.push(checkboxes[i].inputMethodId); | |
714 } | |
715 } | |
716 var languageOptionsList = $('language-options-list'); | |
717 languageOptionsList.updateDeletable(); | |
718 }, | |
719 | |
720 /** | |
721 * Filters bad preload engines in case bad preload engines are | |
722 * stored in the preference. Removes duplicates as well. | |
723 * @param {Array} preloadEngines List of preload engines. | |
724 * @private | |
725 */ | |
726 filterBadPreloadEngines_: function(preloadEngines) { | |
727 // Convert the list into a dictonary for simpler lookup. | |
728 var dictionary = {}; | |
729 for (var i = 0; i < templateData.inputMethodList.length; i++) { | |
730 dictionary[templateData.inputMethodList[i].id] = true; | |
731 } | |
732 | |
733 var filteredPreloadEngines = []; | |
734 var seen = {}; | |
735 for (var i = 0; i < preloadEngines.length; i++) { | |
736 // Check if the preload engine is present in the | |
737 // dictionary, and not duplicate. Otherwise, skip it. | |
738 if (preloadEngines[i] in dictionary && !(preloadEngines[i] in seen)) { | |
739 filteredPreloadEngines.push(preloadEngines[i]); | |
740 seen[preloadEngines[i]] = true; | |
741 } | |
742 } | |
743 return filteredPreloadEngines; | |
744 }, | |
745 | |
746 // TODO(kochi): This is an adapted copy from new_tab.js. | |
747 // If this will go as final UI, refactor this to share the component with | |
748 // new new tab page. | |
749 /** | |
750 * Shows notification | |
751 * @private | |
752 */ | |
753 notificationTimeout_: null, | |
754 showNotification_ : function(text, actionText, opt_delay) { | |
755 var notificationElement = $('notification'); | |
756 var actionLink = notificationElement.querySelector('.link-color'); | |
757 var delay = opt_delay || 10000; | |
758 | |
759 function show() { | |
760 window.clearTimeout(this.notificationTimeout_); | |
761 notificationElement.classList.add('show'); | |
762 document.body.classList.add('notification-shown'); | |
763 } | |
764 | |
765 function hide() { | |
766 window.clearTimeout(this.notificationTimeout_); | |
767 notificationElement.classList.remove('show'); | |
768 document.body.classList.remove('notification-shown'); | |
769 // Prevent tabbing to the hidden link. | |
770 actionLink.tabIndex = -1; | |
771 // Setting tabIndex to -1 only prevents future tabbing to it. If, | |
772 // however, the user switches window or a tab and then moves back to | |
773 // this tab the element may gain focus. We therefore make sure that we | |
774 // blur the element so that the element focus is not restored when | |
775 // coming back to this window. | |
776 actionLink.blur(); | |
777 } | |
778 | |
779 function delayedHide() { | |
780 this.notificationTimeout_ = window.setTimeout(hide, delay); | |
781 } | |
782 | |
783 notificationElement.firstElementChild.textContent = text; | |
784 actionLink.textContent = actionText; | |
785 | |
786 actionLink.onclick = hide; | |
787 actionLink.onkeydown = function(e) { | |
788 if (e.keyIdentifier == 'Enter') { | |
789 hide(); | |
790 } | |
791 }; | |
792 notificationElement.onmouseover = show; | |
793 notificationElement.onmouseout = delayedHide; | |
794 actionLink.onfocus = show; | |
795 actionLink.onblur = delayedHide; | |
796 // Enable tabbing to the link now that it is shown. | |
797 actionLink.tabIndex = 0; | |
798 | |
799 show(); | |
800 delayedHide(); | |
801 } | |
802 }; | |
803 | |
804 /** | |
805 * Chrome callback for when the UI language preference is saved. | |
806 */ | |
807 LanguageOptions.uiLanguageSaved = function() { | |
808 $('language-options-ui-language-button').style.display = 'none'; | |
809 $('language-options-ui-notification-bar').style.display = 'block'; | |
810 }; | |
811 | |
812 // Export | |
813 return { | |
814 LanguageOptions: LanguageOptions | |
815 }; | |
816 }); | |
OLD | NEW |