blob: 43d936c24d2a35e28b0fcbc57c109e0f5b61af11 [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview This file contains NaclMozc option page implementation.
*
* TODO(horo): Write tests of option_page.js.
*
*/
'use strict';
/**
* Default value of configuration.
* These values must be same as defined in config.proto.
* @const
* @type {!Object.<string, string|number|boolean>}
* @private
*/
mozc.DEFAULT_CONFIG_ = {
'verbose_level': 0,
'incognito_mode': false,
'check_default': true,
'presentation_mode': false,
'preedit_method': 'ROMAN',
'session_keymap': 'CHROMEOS',
'custom_keymap_table': '',
'punctuation_method': 'KUTEN_TOUTEN',
'symbol_method': 'CORNER_BRACKET_MIDDLE_DOT',
'space_character_form': 'FUNDAMENTAL_INPUT_MODE',
'use_keyboard_to_change_preedit_method': false,
'history_learning_level': 'DEFAULT_HISTORY',
'selection_shortcut': 'SHORTCUT_123456789',
'use_auto_ime_turn_off': true,
'shift_key_mode_switch': 'ASCII_INPUT_MODE',
'numpad_character_form': 'NUMPAD_HALF_WIDTH',
'use_auto_conversion': false,
'auto_conversion_key': 13,
'yen_sign_character': 'YEN_SIGN',
'use_japanese_layout': false,
'use_date_conversion': true,
'use_single_kanji_conversion': true,
'use_symbol_conversion': true,
'use_number_conversion': true,
'use_emoticon_conversion': true,
'use_calculator': true,
'use_t13n_conversion': true,
'use_zip_code_conversion': true,
'use_spelling_correction': true,
'use_history_suggest': true,
'use_dictionary_suggest': true,
'use_realtime_conversion': true,
'suggestions_size': 3,
'allow_cloud_handwriting': false,
'upload_usage_stats': false
};
/**
* Option title information data.
* @const
* @type {!Array.<!Object>}
* @private
*/
mozc.OPTION_TITLES_ = [
{
id: 'settings_title',
name: chrome.i18n.getMessage('configSettingsTitle')
},
{
id: 'basics_title',
name: chrome.i18n.getMessage('configBasicsTitle')
},
{
id: 'input_assistance_title',
name: chrome.i18n.getMessage('configInputAssistanceTitle')
},
{
id: 'suggest_title',
name: chrome.i18n.getMessage('configSuggestTitle')
},
{
id: 'privacy_title',
name: chrome.i18n.getMessage('configPrivacyTitle')
},
{
id: 'credits_title',
name: chrome.i18n.getMessage('configCreditsDescription')
},
{
id: 'oss_credits_title',
name: chrome.i18n.getMessage('configOssCreditsDescription')
},
{
id: 'clear_history_title',
name: chrome.i18n.getMessage('configClearHistoryTitle')
},
{
id: 'clear_history_message',
name: chrome.i18n.getMessage('configClearHistoryMessage')
},
{
id: 'clear_history_conversion_history_label',
name: chrome.i18n.getMessage('configClearHistoryConversionHistory')
},
{
id: 'clear_history_suggestion_history_label',
name: chrome.i18n.getMessage('configClearHistorySuggestionHistory')
},
{
id: 'dictionary_tool_title',
name: chrome.i18n.getMessage('configDictionaryToolTitle')
},
{
id: 'dictionary_tool_description',
name: chrome.i18n.getMessage('configDictionaryToolDescription')
},
{
id: 'dictionary_tool_page_title',
name: chrome.i18n.getMessage('dictionaryToolPageTitle')
},
{
id: 'dictionary_tool_dictionary_list_title',
name: chrome.i18n.getMessage('dictionaryToolDictionaryListTitle')
},
{
id: 'dictionary_tool_reading_title',
name: chrome.i18n.getMessage('dictionaryToolReadingTitle')
},
{
id: 'dictionary_tool_word_title',
name: chrome.i18n.getMessage('dictionaryToolWordTitle')
},
{
id: 'dictionary_tool_category_title',
name: chrome.i18n.getMessage('dictionaryToolCategoryTitle')
},
{
id: 'dictionary_tool_comment_title',
name: chrome.i18n.getMessage('dictionaryToolCommentTitle')
},
{
id: 'dictionary_tool_dictionary_menu_title',
name: chrome.i18n.getMessage('dictionaryToolMenuTitle')
}
];
/**
* Option checkbox information data.
* @const
* @type {!Array.<!Object>}
* @private
*/
mozc.OPTION_CHECKBOXES_ = [
{
id: 'upload_usage_stats',
configId: 'upload_usage_stats',
configType: 'general_config',
name: chrome.i18n.getMessage('configUploadUsageStats'),
// Disable 'upload_usage_stats' checkbox in OSS Mozc.
disabled: (chrome.i18n.getMessage('branding') == 'Mozc')
},
{
id: 'incognito_mode',
configId: 'incognito_mode',
name: chrome.i18n.getMessage('configIncognitoMode')
},
{
id: 'use_auto_ime_turn_off',
configId: 'use_auto_ime_turn_off',
name: chrome.i18n.getMessage('configUseAutoImeTurnOff')
},
{
id: 'use_history_suggest',
configId: 'use_history_suggest',
name: chrome.i18n.getMessage('configUseHistorySuggest')
},
{
id: 'use_dictionary_suggest',
configId: 'use_dictionary_suggest',
name: chrome.i18n.getMessage('configUseDictionarySuggest')
}
];
/**
* Option selection information data.
* @const
* @type {!Array.<!Object>}
* @private
*/
mozc.OPTION_SELECTIONS_ = [
{
id: 'punctuation_method',
configId: 'punctuation_method',
name: chrome.i18n.getMessage('configPunctuationMethod'),
items: [
{name: '\u3001\u3002', value: 'KUTEN_TOUTEN'}, // '、。'
{name: '\uFF0C\uFF0E', value: 'COMMA_PERIOD'}, // ',.'
{name: '\u3001\uFF0E', value: 'KUTEN_PERIOD'}, // '、.'
{name: '\uFF0C\u3002', value: 'COMMA_TOUTEN'} // ',。'
]
},
{
id: 'preedit_method',
configId: 'preedit_method',
name: chrome.i18n.getMessage('configPreeditMethod'),
items: [
{
name: chrome.i18n.getMessage('configPreeditMethodRomaji'),
value: 'ROMAN'
},
{name: chrome.i18n.getMessage('configPreeditMethodKana'), value: 'KANA'}
]
},
{
id: 'symbol_method',
configId: 'symbol_method',
name: chrome.i18n.getMessage('configSymbolMethod'),
items: [
// '「」・'
{name: '\u300C\u300D\u30FB', value: 'CORNER_BRACKET_MIDDLE_DOT'},
{name: '\uFF3B\uFF3D\uFF0F', value: 'SQUARE_BRACKET_SLASH'}, // '[]/'
{name: '\u300C\u300D\uFF0F', value: 'CORNER_BRACKET_SLASH'}, // '「」/'
{name: '\uFF3B\uFF3D\u30FB', value: 'SQUARE_BRACKET_MIDDLE_DOT'} // '[]・'
]
},
{
id: 'space_character_form',
configId: 'space_character_form',
name: chrome.i18n.getMessage('configSpaceCharacterForm'),
items: [
{
name: chrome.i18n.getMessage('configSpaceCharacterFormFollow'),
value: 'FUNDAMENTAL_INPUT_MODE'
},
{
name: chrome.i18n.getMessage('configSpaceCharacterFormFull'),
value: 'FUNDAMENTAL_FULL_WIDTH'
},
{
name: chrome.i18n.getMessage('configSpaceCharacterFormHalf'),
value: 'FUNDAMENTAL_HALF_WIDTH'
}
]
},
{
id: 'selection_shortcut',
configId: 'selection_shortcut',
name: chrome.i18n.getMessage('configSelectionShortcut'),
items: [
{
name: chrome.i18n.getMessage('configSelectionShortcutNo'),
value: 'NO_SHORTCUT'
},
{name: '1 -- 9', value: 'SHORTCUT_123456789'},
{name: 'A -- L', value: 'SHORTCUT_ASDFGHJKL'}
]
},
{
id: 'shift_key_mode_switch',
configId: 'shift_key_mode_switch',
name: chrome.i18n.getMessage('configShiftKeyModeSwitch'),
items: [
{
name: chrome.i18n.getMessage('configShiftKeyModeSwitchOff'),
value: 'OFF'
},
{
name: chrome.i18n.getMessage('configShiftKeyModeSwitchAlphanumeric'),
value: 'ASCII_INPUT_MODE'
},
{
name: chrome.i18n.getMessage('configShiftKeyModeSwitchKatakana'),
value: 'KATAKANA_INPUT_MODE'
}
]
},
{
id: 'session_keymap',
configId: 'session_keymap',
name: chrome.i18n.getMessage('configSessionKeymap'),
items: [
{
name: chrome.i18n.getMessage('configSessionKeymapChromeOs'),
value: 'CHROMEOS'
},
{
name: chrome.i18n.getMessage('configSessionKeymapAtok'),
value: 'ATOK'
},
{
name: chrome.i18n.getMessage('configSessionKeymapMsIme'),
value: 'MSIME'
},
{
name: chrome.i18n.getMessage('configSessionKeymapKotoeri'),
value: 'KOTOERI'
}
]
}
];
/**
* Option number information data.
* @const
* @type {!Array.<!Object>}
* @private
*/
mozc.OPTION_NUMBERS_ = [
{
id: 'suggestions_size',
configId: 'suggestions_size',
name: chrome.i18n.getMessage('configSuggestionsSize'),
min: 1,
max: 9
}
];
/**
* Option button information data.
* @const
* @type {!Array.<!Object>}
* @private
*/
mozc.OPTION_BUTTONS_ = [
{
id: 'clear_history_open',
name: chrome.i18n.getMessage('configClearHistory')
},
{
id: 'clear_history_close'
},
{
id: 'clear_history_ok',
name: chrome.i18n.getMessage('configClearHistoryOkButton')
},
{
id: 'clear_history_cancel',
name: chrome.i18n.getMessage('configClearHistoryCancelButton')
},
{
id: 'dictionary_tool_open_button',
name: chrome.i18n.getMessage('configDictionaryToolButton')
},
{
id: 'export_dictionary_button',
name: chrome.i18n.getMessage('dictionaryToolExportButton')
},
{
id: 'import_dictionary_button',
name: chrome.i18n.getMessage('dictionaryToolImportButton')
},
{
id: 'dictionary_tool_done_button',
name: chrome.i18n.getMessage('dictionaryToolDoneButton')
},
{
id: 'dictionary_tool_close'
}
];
/**
* An empty constructor.
* @param {!mozc.NaclMozc} naclMozc NaCl Mozc.
* @param {!Window} optionWindow Window object of the option page.
* @constructor
* @struct
* @const
*/
mozc.OptionPage = function(naclMozc, optionWindow) {
/**
* NaclMozc object.
* This value will be null when the option page is unloaded.
* @type {mozc.NaclMozc}
* @private
*/
this.naclMozc_ = naclMozc;
/**
* Window object of the option page.
* This value will be null when the option page is unloaded.
* @type {Window}
* @private
*/
this.window_ = optionWindow;
/**
* Document object of the option page.
* This value will be null when the option page is unloaded.
* @type {Document}
* @private
*/
this.document_ = optionWindow.document;
/**
* Console object of the option page.
* This value will be null when the option page is unloaded.
* @type {Object}
* @private
*/
this.console_ = optionWindow.console;
/**
* Stack of Esc key handlers. An Esc key handler is pushed to it when an
* dialog box is opend and the handler will be popped when the dialog box is
* closed. It is used to close the dialog when the user presses Esc key.
* @type {!Array.<!Function>}
* @private
*/
this.escapeKeyHandlers_ = [];
/**
* Dictionary tool object.
* @type {!mozc.DictionaryTool}
* @private
*/
this.dictionaryTool_ = new mozc.DictionaryTool(naclMozc, optionWindow, this);
};
/**
* Initializes the option page.
*/
mozc.OptionPage.prototype.initialize = function() {
this.window_.addEventListener('beforeunload',
this.unload_.bind(this),
true);
if (!this.naclMozc_) {
console.error('The option page is already unloaded.');
return;
}
this.initPages_();
this.naclMozc_.callWhenInitialized((function() {
this.naclMozc_.getPosList((function(message) {
this.dictionaryTool_.setPosList(message['posList']);
this.naclMozc_.getConfig((function(response) {
this.onConfigLoaded_(response);
this.document_.body.style.visibility = 'visible';
}).bind(this));
}).bind(this));
// Outputs the version information to JavaScript console.
this.naclMozc_.getVersionInfo((function(message) {
this.console_.log(JSON.stringify(message));
}).bind(this));
}).bind(this));
};
/**
* Unloads the option page.
* @private
*/
mozc.OptionPage.prototype.unload_ = function() {
this.window_ = null;
this.naclMozc_ = null;
this.document_ = null;
this.console_ = null;
};
/**
* Gets whether the option page is unloaded.
* @return {boolean} Whether the option page is already unloaded.
*/
mozc.OptionPage.prototype.isUnloaded = function() {
return this.naclMozc_ == null;
};
/**
* Creates an Option element.
* @param {string} name Name of the option.
* @param {string} value Value of the option.
* @return {!Element} Created Option element.
*/
mozc.OptionPage.prototype.createOptionElement = function(name, value) {
var option = this.document_.createElement('option');
option.appendChild(this.document_.createTextNode(name));
option.setAttribute('value', value);
return option;
};
/**
* Initializes the page.
* @private
*/
mozc.OptionPage.prototype.initPages_ = function() {
this.document_.title = chrome.i18n.getMessage('configSettingsTitle');
for (var i = 0; i < mozc.OPTION_TITLES_.length; ++i) {
var optionTitle = mozc.OPTION_TITLES_[i];
this.document_.getElementById(optionTitle.id).innerHTML =
optionTitle.name;
}
// A checkbox (id:'CHECK_BOX_ID') is in a DIV (id:'CHECK_BOX_ID_div') and has
// a label (id:'CHECK_BOX_ID_label').
// <div id='CHECK_BOX_ID_div'>
// <span>
// <input type='checkbox' id='CHECK_BOX_ID'>
// <span>
// <label for='CHECK_BOX_ID' id='CHECK_BOX_ID_label'>...</label>
// </span>
// </span>
// </div>
for (var i = 0; i < mozc.OPTION_CHECKBOXES_.length; ++i) {
var optionCheckbox = mozc.OPTION_CHECKBOXES_[i];
if (optionCheckbox.disabled) {
this.document_.getElementById(optionCheckbox.id + '_div').style
.visibility = 'hidden';
}
this.document_.getElementById(optionCheckbox.id + '_label').innerHTML =
optionCheckbox.name;
this.document_.getElementById(optionCheckbox.id).addEventListener(
'change', this.saveConfig_.bind(this), true);
}
// A selection (id:'SELECTION_ID') is in a DIV (id:'SELECTION_ID_div') and has
// a label (id:'SELECTION_ID_label')
// <div id='SELECTION_ID_div'>
// <span class='controlled-setting-with-label'>
// <span class='selection-label' id='SELECTION_ID_label'>...</span>
// <select id='SELECTION_ID'></select>
// </span>
// </div>
for (var i = 0; i < mozc.OPTION_SELECTIONS_.length; ++i) {
var optionSelection = mozc.OPTION_SELECTIONS_[i];
this.document_.getElementById(optionSelection.id + '_label').innerHTML =
optionSelection.name;
var selectionElement = this.document_.getElementById(optionSelection.id);
selectionElement.innerHTML = optionSelection.name;
while (selectionElement.hasChildNodes()) {
selectionElement.removeChild(selectionElement.firstChild);
}
for (var j = 0; j < optionSelection.items.length; ++j) {
selectionElement.appendChild(this.createOptionElement(
optionSelection.items[j].name,
optionSelection.items[j].value));
}
selectionElement.addEventListener(
'change', this.saveConfig_.bind(this), true);
}
// We use a select element for number selection.
// A selection (id:'NUMBER_ID') is in a DIV (id:'NUMBER_ID_div') and has a
// label (id:'NUMBER_ID_label')
// <div id='NUMBER_ID_div'>
// <span class='controlled-setting-with-label'>
// <span class='selection-label' id='NUMBER_ID_label'>...</span>
// <select id='NUMBER_ID'></select>
// </span>
// </div>
for (var i = 0; i < mozc.OPTION_NUMBERS_.length; ++i) {
var optionNumber = mozc.OPTION_NUMBERS_[i];
this.document_.getElementById(optionNumber.id + '_label').innerHTML =
optionNumber.name;
var selectionElement = this.document_.getElementById(optionNumber.id);
selectionElement.innerHTML = optionNumber.name;
while (selectionElement.hasChildNodes()) {
selectionElement.removeChild(selectionElement.firstChild);
}
for (var j = optionNumber.min; j <= optionNumber.max; ++j) {
selectionElement.appendChild(this.createOptionElement(j, j));
}
selectionElement.addEventListener(
'change', this.saveConfig_.bind(this), true);
}
// A button (id:'BUTTON_ID') is in a DIV (id:'BUTTON_ID_div').
// <div id='BUTTON_ID_div'>
// <span class='controlled-setting-with-label'>
// <input type='button' id='BUTTON_ID' value='...'>
// </span>
// </div>
for (var i = 0; i < mozc.OPTION_BUTTONS_.length; ++i) {
var optionButton = mozc.OPTION_BUTTONS_[i];
var buttonElement = this.document_.getElementById(optionButton.id);
if (optionButton.name) {
buttonElement.value = optionButton.name;
}
buttonElement.addEventListener('click',
this.onButtonClick_.bind(this,
optionButton.id),
true);
}
// Disables clear_history_ok button according to check boxes in Clear History
// dialog.
this.document_.getElementById('clear_history_conversion_history')
.addEventListener('change',
this.updateClearHistoryOkButton_.bind(this),
true);
this.document_.getElementById('clear_history_suggestion_history')
.addEventListener('change',
this.updateClearHistoryOkButton_.bind(this),
true);
this.document_.getElementById('dictionary_tool_dictionary_list')
.addEventListener(
'keydown',
this.dictionaryTool_.onDictionaryToolDictionaryListKeyDown.bind(
this.dictionaryTool_),
true);
var newReadingInput =
this.document_.getElementById('dictionary_tool_reading_new_input');
newReadingInput.addEventListener(
'input',
this.dictionaryTool_.onDictionaryReadingInputChanged.bind(
this.dictionaryTool_, newReadingInput),
true);
newReadingInput.addEventListener(
'blur',
this.dictionaryTool_.onDictionaryNewEntryLostFocus.bind(
this.dictionaryTool_),
true);
this.document_.getElementById('dictionary_tool_word_new_input')
.addEventListener(
'blur',
this.dictionaryTool_.onDictionaryNewEntryLostFocus.bind(
this.dictionaryTool_),
true);
this.document_.getElementById('dictionary_tool_category_new_select')
.addEventListener(
'blur',
this.dictionaryTool_.onDictionaryNewEntryLostFocus.bind(
this.dictionaryTool_),
true);
this.document_.getElementById('dictionary_tool_comment_new_input')
.addEventListener(
'blur',
this.dictionaryTool_.onDictionaryNewEntryLostFocus.bind(
this.dictionaryTool_),
true);
this.document_.addEventListener(
'keydown', this.onKeyDown_.bind(this), false);
};
/**
* Called when the configuration is loaded.
* @param {Object} response Response data of GET_CONFIG from NaCl module.
* @private
*/
mozc.OptionPage.prototype.onConfigLoaded_ = function(response) {
if (this.isUnloaded()) {
console.error('The option page is already unloaded.');
return;
}
var config = response['output']['config'];
for (var i = 0; i < mozc.OPTION_CHECKBOXES_.length; ++i) {
var optionCheckbox = mozc.OPTION_CHECKBOXES_[i];
if (optionCheckbox.disabled) {
continue;
}
var value = false;
if (optionCheckbox.configType == 'general_config') {
value =
((config['general_config'] != undefined) &&
(config['general_config'][optionCheckbox.configId] != undefined)) ?
config['general_config'][optionCheckbox.configId] :
mozc.DEFAULT_CONFIG_[optionCheckbox.configId];
} else {
value = (config[optionCheckbox.configId] != undefined) ?
config[optionCheckbox.configId] :
mozc.DEFAULT_CONFIG_[optionCheckbox.configId];
}
this.document_.getElementById(optionCheckbox.id).checked = value;
}
for (var i = 0; i < mozc.OPTION_SELECTIONS_.length; ++i) {
var optionSelection = mozc.OPTION_SELECTIONS_[i];
var value = (config[optionSelection.configId] != undefined) ?
config[optionSelection.configId] :
mozc.DEFAULT_CONFIG_[optionSelection.configId];
this.document_.getElementById(optionSelection.id).value = value;
}
for (var i = 0; i < mozc.OPTION_NUMBERS_.length; ++i) {
var optionNumber = mozc.OPTION_NUMBERS_[i];
var value = (config[optionNumber.configId] != undefined) ?
config[optionNumber.configId] :
mozc.DEFAULT_CONFIG_[optionNumber.configId];
this.document_.getElementById(optionNumber.id).value = value;
}
};
/**
* Saves the configuration.
* @private
*/
mozc.OptionPage.prototype.saveConfig_ = function() {
if (this.isUnloaded()) {
console.error('The option page is already unloaded.');
return;
}
this.naclMozc_.getConfig((function(response) {
var config = response['output']['config'];
for (var i = 0; i < mozc.OPTION_CHECKBOXES_.length; ++i) {
var optionCheckbox = mozc.OPTION_CHECKBOXES_[i];
if (optionCheckbox.disabled) {
continue;
}
if (optionCheckbox.configType == 'general_config') {
if (config['general_config'] == undefined) {
config['general_config'] = {};
}
config['general_config'][optionCheckbox.configId] =
this.document_.getElementById(optionCheckbox.id).checked;
} else {
config[optionCheckbox.configId] =
this.document_.getElementById(optionCheckbox.id).checked;
}
}
for (var i = 0; i < mozc.OPTION_NUMBERS_.length; ++i) {
var optionNumber = mozc.OPTION_NUMBERS_[i];
config[optionNumber.configId] =
Number(this.document_.getElementById(optionNumber.id).value);
}
for (var i = 0; i < mozc.OPTION_SELECTIONS_.length; ++i) {
var optionSelection = mozc.OPTION_SELECTIONS_[i];
config[optionSelection.configId] =
this.document_.getElementById(optionSelection.id).value;
}
this.console_.log(config);
this.naclMozc_.setConfig(
config,
(function() {this.naclMozc_.sendReload()}).bind(this));
}).bind(this));
};
/**
* Called when the user presses a key.
* @param {Event} event Event object passed from browser.
* @private
*/
mozc.OptionPage.prototype.onKeyDown_ = function(event) {
if (event.keyCode == 27) { // Escape
if (this.escapeKeyHandlers_.length) {
this.escapeKeyHandlers_[this.escapeKeyHandlers_.length - 1]();
}
}
};
/**
* Pop Esc key handler.
*/
mozc.OptionPage.prototype.popEscapeKeyHandler = function() {
this.escapeKeyHandlers_.pop();
};
/**
* Push Esc key handler.
* @param {!Function} handler Esc key handler.
*/
mozc.OptionPage.prototype.pushEscapeKeyHandler = function(handler) {
this.escapeKeyHandlers_.push(handler);
};
/**
* Enables the dom element which is specified by id in the option page.
* @param {string} id The element ID.
*/
mozc.OptionPage.prototype.enableElementById = function(id) {
this.document_.getElementById(id).disabled = false;
};
/**
* Disables the dom element which is specified by id in the option page.
* @param {string} id The element ID.
*/
mozc.OptionPage.prototype.disableElementById = function(id) {
this.document_.getElementById(id).disabled = true;
};
/**
* Shows the dom element which is specified by id in the option page.
* @param {string} id The element ID.
* @private
*/
mozc.OptionPage.prototype.showElementById_ = function(id) {
this.document_.getElementById(id).style.display = 'inline';
};
/**
* Hides the dom element which is specified by id in the option page.
* @param {string} id The element ID.
* @private
*/
mozc.OptionPage.prototype.hideElementById_ = function(id) {
this.document_.getElementById(id).style.display = 'none';
};
/**
* Shows the overlay element which is specified by id in the option page.
* @param {string} id The element ID.
*/
mozc.OptionPage.prototype.showOverlayElementById = function(id) {
this.freezeMainDiv_();
this.document_.getElementById(id).style.visibility = 'visible';
};
/**
* Hides the overlay element which is specified by id in the option page.
* @param {string} id The element ID.
*/
mozc.OptionPage.prototype.hideOverlayElementById = function(id) {
this.document_.getElementById(id).style.visibility = 'hidden';
this.unfreezeMainDiv_();
};
/**
* Shows a confirm dialog box. This method makes callerPageId element
* unfocusable while showing the dialog box.
* @param {string} callerPageId The ID of caller page.
* @param {string} title The title of the dialog box.
* @param {string} message The message in the dialog box.
* @param {!function(?boolean)} callback Function to be called with the result.
*/
mozc.OptionPage.prototype.showConfirm = function(callerPageId,
title,
message,
callback) {
this.setChildNodesUnfocusableByTabKeyById(callerPageId);
var confirmOverlay = this.document_.createElement('div');
confirmOverlay.classList.add('overlay', 'confirm_overlay');
var confirmPage = this.document_.createElement('div');
confirmPage.classList.add('overlay_page', 'confirm_page');
var closeDiv = this.document_.createElement('div');
closeDiv.classList.add('close_button');
var section = this.document_.createElement('section');
var confirmTitle = this.document_.createElement('div');
confirmTitle.classList.add('confirm_title');
confirmTitle.appendChild(this.document_.createTextNode(title));
var confirmMessage = this.document_.createElement('div');
confirmMessage.classList.add('confirm_message_div');
confirmMessage.appendChild(this.document_.createTextNode(message));
var confirmOkCancelDiv = this.document_.createElement('div');
confirmOkCancelDiv.classList.add('confirm_ok_cancel_div');
var confirmOkButton = this.document_.createElement('input');
confirmOkButton.classList.add('confirm_ok_button');
confirmOkButton.type = 'button';
confirmOkButton.value = chrome.i18n.getMessage('configDialogOk');
var confirmCancelButton = this.document_.createElement('input');
confirmCancelButton.classList.add('confirm_cancel_button');
confirmCancelButton.type = 'button';
confirmCancelButton.value = chrome.i18n.getMessage('configDialogCancel');
confirmOkCancelDiv.appendChild(confirmOkButton);
confirmOkCancelDiv.appendChild(confirmCancelButton);
section.appendChild(confirmTitle);
section.appendChild(confirmMessage);
section.appendChild(confirmOkCancelDiv);
confirmPage.appendChild(closeDiv);
confirmPage.appendChild(section);
confirmOverlay.appendChild(confirmPage);
var okCallback =
(function(overlay, pageId, callbackFunc) {
this.popEscapeKeyHandler();
this.document_.body.removeChild(overlay);
this.setChildNodesFocusableByTabKeyById(pageId);
callbackFunc(true);
}).bind(this, confirmOverlay, callerPageId, callback);
var cancelCallback =
(function(overlay, pageId, callbackFunc) {
this.popEscapeKeyHandler();
this.document_.body.removeChild(overlay);
this.setChildNodesFocusableByTabKeyById(pageId);
callbackFunc(false);
}).bind(this, confirmOverlay, callerPageId, callback);
closeDiv.addEventListener('click', cancelCallback, true);
confirmOkButton.addEventListener('click', okCallback, true);
confirmCancelButton.addEventListener('click', cancelCallback, true);
this.pushEscapeKeyHandler(cancelCallback);
this.document_.body.appendChild(confirmOverlay);
confirmOkButton.focus();
};
/**
* Shows a prompt dialog box. This method makes callerPageId element unfocusable
* while showing the dialog box.
* @param {string} callerPageId The ID of caller page.
* @param {string} title The title of the dialog box.
* @param {string} message The message in the dialog box.
* @param {string} defaultValue The default value.
* @param {!function(?string)} callback Function to be called with the result.
* If the user clicks the cancel button the result will be null.
*/
mozc.OptionPage.prototype.showPrompt = function(callerPageId,
title,
message,
defaultValue,
callback) {
this.setChildNodesUnfocusableByTabKeyById(callerPageId);
var promptOverlay = this.document_.createElement('div');
promptOverlay.classList.add('overlay', 'prompt_overlay');
var promptPage = this.document_.createElement('div');
promptPage.classList.add('overlay_page', 'prompt_page');
var closeDiv = this.document_.createElement('div');
closeDiv.classList.add('close_button');
var section = this.document_.createElement('section');
var promptTitle = this.document_.createElement('div');
promptTitle.classList.add('prompt_title');
promptTitle.appendChild(this.document_.createTextNode(title));
var promptMessage = this.document_.createElement('div');
promptMessage.classList.add('prompt_message_div');
promptMessage.appendChild(this.document_.createTextNode(message));
var promptOkCancelDiv = this.document_.createElement('div');
promptOkCancelDiv.classList.add('prompt_ok_cancel_div');
var promptInputDiv = this.document_.createElement('div');
promptInputDiv.classList.add('prompt_input_div');
var promptInput = this.document_.createElement('input');
promptInput.classList.add('prompt_input');
promptInput.type = 'text';
promptInput.value = defaultValue;
promptInputDiv.appendChild(promptInput);
var promptOkButton = this.document_.createElement('input');
promptOkButton.classList.add('prompt_ok_button');
promptOkButton.type = 'button';
promptOkButton.value = chrome.i18n.getMessage('configDialogOk');
var promptCancelButton = this.document_.createElement('input');
promptCancelButton.classList.add('prompt_cancel_button');
promptCancelButton.type = 'button';
promptCancelButton.value = chrome.i18n.getMessage('configDialogCancel');
promptOkCancelDiv.appendChild(promptOkButton);
promptOkCancelDiv.appendChild(promptCancelButton);
section.appendChild(promptTitle);
section.appendChild(promptMessage);
section.appendChild(promptInputDiv);
section.appendChild(promptOkCancelDiv);
promptPage.appendChild(closeDiv);
promptPage.appendChild(section);
promptOverlay.appendChild(promptPage);
var okCallback =
(function(overlay, pageId, callbackFunc, input) {
this.popEscapeKeyHandler();
this.document_.body.removeChild(overlay);
this.setChildNodesFocusableByTabKeyById(pageId);
callbackFunc(input.value);
}).bind(this, promptOverlay, callerPageId, callback, promptInput);
var cancelCallback =
(function(overlay, pageId, callbackFunc) {
this.popEscapeKeyHandler();
this.document_.body.removeChild(overlay);
this.setChildNodesFocusableByTabKeyById(pageId);
callbackFunc(null);
}).bind(this, promptOverlay, callerPageId, callback);
closeDiv.addEventListener('click', cancelCallback, true);
promptOkButton.addEventListener('click', okCallback, true);
promptCancelButton.addEventListener('click', cancelCallback, true);
this.pushEscapeKeyHandler(cancelCallback);
this.document_.body.appendChild(promptOverlay);
promptInput.focus();
};
/**
* Shows an alert dialog box. This method makes callerPageId element unfocusable
* while showing the dialog box.
* @param {string} callerPageId The ID of caller page.
* @param {string} title The title of the dialog box.
* @param {string} message The message in the dialog box.
* @param {!function()=} opt_callback Function to be called when closed.
*/
mozc.OptionPage.prototype.showAlert = function(callerPageId,
title,
message,
opt_callback) {
this.setChildNodesUnfocusableByTabKeyById(callerPageId);
var alertOverlay = this.document_.createElement('div');
alertOverlay.classList.add('overlay', 'alert_overlay');
var alertPage = this.document_.createElement('div');
alertPage.classList.add('overlay_page', 'alert_page');
var closeDiv = this.document_.createElement('div');
closeDiv.classList.add('close_button');
var section = this.document_.createElement('section');
var alertTitle = this.document_.createElement('div');
alertTitle.classList.add('alert_title');
alertTitle.appendChild(this.document_.createTextNode(title));
var alertMessage = this.document_.createElement('div');
alertMessage.classList.add('alert_message_div');
alertMessage.appendChild(this.document_.createTextNode(message));
var alertOkDiv = this.document_.createElement('div');
alertOkDiv.classList.add('alert_ok_div');
var alertOkButton = this.document_.createElement('input');
alertOkButton.classList.add('alert_ok_button');
alertOkButton.type = 'button';
alertOkButton.value = chrome.i18n.getMessage('configDialogOk');
alertOkDiv.appendChild(alertOkButton);
section.appendChild(alertTitle);
section.appendChild(alertMessage);
section.appendChild(alertOkDiv);
alertPage.appendChild(closeDiv);
alertPage.appendChild(section);
alertOverlay.appendChild(alertPage);
var okCallback =
(function(overlay, pageId, opt_callbackFunc) {
this.popEscapeKeyHandler();
this.document_.body.removeChild(overlay);
this.setChildNodesFocusableByTabKeyById(pageId);
if (opt_callbackFunc) {
opt_callbackFunc();
}
}).bind(this, alertOverlay, callerPageId, opt_callback);
closeDiv.addEventListener('click', okCallback, true);
alertOkButton.addEventListener('click', okCallback, true);
this.pushEscapeKeyHandler(okCallback);
this.document_.body.appendChild(alertOverlay);
alertOkButton.focus();
};
/**
* Called when a button is clicked.
* @param {string} buttonId The clicked button ID.
* @private
*/
mozc.OptionPage.prototype.onButtonClick_ = function(buttonId) {
if (buttonId == 'clear_history_open') {
this.onClearHistoryOpenClicked_();
} else if (buttonId == 'clear_history_close') {
this.onClearHistoryCancelClicked_();
} else if (buttonId == 'clear_history_ok') {
this.onClearHistoryOkClicked_();
} else if (buttonId == 'clear_history_cancel') {
this.onClearHistoryCancelClicked_();
} else if (buttonId == 'dictionary_tool_open_button') {
this.dictionaryTool_.onDictionaryToolOpenButtonClicked();
} else if (buttonId == 'dictionary_tool_done_button') {
this.dictionaryTool_.onDictionaryToolDoneButtonClicked();
} else if (buttonId == 'dictionary_tool_close') {
this.dictionaryTool_.onDictionaryToolDoneButtonClicked();
} else if (buttonId == 'export_dictionary_button') {
this.dictionaryTool_.onDictionaryToolExportButtonClicked();
} else if (buttonId == 'import_dictionary_button') {
this.dictionaryTool_.onDictionaryToolImportButtonClicked();
}
};
/**
* Called when clear_history_open button is clicked.
* This method opens clear history dialog.
* @private
*/
mozc.OptionPage.prototype.onClearHistoryOpenClicked_ = function() {
this.pushEscapeKeyHandler(this.onClearHistoryCancelClicked_.bind(this));
this.document_.getElementById('clear_history_conversion_history').checked =
true;
this.document_.getElementById('clear_history_suggestion_history').checked =
true;
this.showOverlayElementById('clear_history_overlay');
this.document_.getElementById('clear_history_cancel').focus();
};
/**
* Disables clear_history_ok button according to check boxes in Clear History
* dialog.
* @private
*/
mozc.OptionPage.prototype.updateClearHistoryOkButton_ = function() {
this.document_.getElementById('clear_history_ok').disabled =
!this.document_.getElementById('clear_history_conversion_history')
.checked &&
!this.document_.getElementById('clear_history_suggestion_history')
.checked;
};
/**
* Called when clear_history_ok button is clicked.
* This method calls CLEAR_USER_HISTORY and CLEAR_USER_PREDICTION command
* according to clear_history_conversion_history and
* clear_history_suggestion_history check boxes.
* @private
*/
mozc.OptionPage.prototype.onClearHistoryOkClicked_ = function() {
if (this.document_.getElementById(
'clear_history_conversion_history').checked) {
this.naclMozc_.clearUserHistory();
}
if (this.document_.getElementById(
'clear_history_suggestion_history').checked) {
this.naclMozc_.clearUserPrediction();
}
this.popEscapeKeyHandler();
this.hideOverlayElementById('clear_history_overlay');
this.document_.getElementById('clear_history_open').focus();
};
/**
* Called when clear_history_cancel button or clear_history_close button is
* clicked or the user presses Esc key while clear history dialog is opened.
* This method closes the clear history dialog.
* @private
*/
mozc.OptionPage.prototype.onClearHistoryCancelClicked_ = function() {
this.popEscapeKeyHandler();
this.hideOverlayElementById('clear_history_overlay');
this.document_.getElementById('clear_history_open').focus();
};
/**
* Sets the tabIndex of the all focusable elements (tabIndex >= 0) in the target
* element -1 to make them unfocusable with tab key.
* @param {string} elementId The ID of target element.
*/
mozc.OptionPage.prototype.setChildNodesUnfocusableByTabKeyById =
function(elementId) {
var element = this.document_.getElementById(elementId);
if (!element) {
return;
}
this.setChildNodesUnfocusableByTabKey_(element);
};
/**
* Resets the tabIndex of the all focusable elements in the target element which
* was set to -1 with setChildNodesUnfocusableByTabKeyById().
* @param {string} elementId The ID of target element.
*/
mozc.OptionPage.prototype.setChildNodesFocusableByTabKeyById =
function(elementId) {
var element = this.document_.getElementById(elementId);
if (!element) {
return;
}
this.setChildNodesFocusableByTabKey_(element);
};
/**
* Sets the tabIndex of the all focusable elements (tabIndex >= 0) in the target
* element -1 to make them unfocusable with tab key.
* @param {!Element} element The target element.
* @private
*/
mozc.OptionPage.prototype.setChildNodesUnfocusableByTabKey_ =
function(element) {
if (element.tabIndex >= 0) {
element.oldTabIndex = element.tabIndex;
element.tabIndex = -1;
}
if (!element.childNodes) {
return;
}
for (var i = 0; i < element.childNodes.length; ++i) {
this.setChildNodesUnfocusableByTabKey_(element.childNodes[i]);
}
};
/**
* Resets the tabIndex of the all focusable elements in the target element which
* was set to -1 with setChildNodesUnfocusableByTabKey_().
* @param {!Element} element The target element.
* @private
*/
mozc.OptionPage.prototype.setChildNodesFocusableByTabKey_ = function(element) {
if (element.oldTabIndex >= 0) {
element.tabIndex = element.oldTabIndex;
element.oldTabIndex = undefined;
}
if (!element.childNodes) {
return;
}
for (var i = 0; i < element.childNodes.length; ++i) {
this.setChildNodesFocusableByTabKey_(element.childNodes[i]);
}
};
/**
* Freezes the main div 'settings_div' to hide scroll bar.
* @private
*/
mozc.OptionPage.prototype.freezeMainDiv_ = function() {
var mainDiv = this.document_.getElementById('settings_div');
if (mainDiv.classList.contains('frozen')) {
return;
}
mainDiv.style.width = this.window_.getComputedStyle(mainDiv).width;
mainDiv.oldScrollTop = this.document_.body.scrollTop;
mainDiv.classList.add('frozen');
var vertical_position =
mainDiv.getBoundingClientRect().top - mainDiv.oldScrollTop;
mainDiv.style.top = vertical_position + 'px';
this.setChildNodesUnfocusableByTabKey_(mainDiv);
};
/**
* Unfreezes the main div 'settings_div' to hide scroll bar.
* @private
*/
mozc.OptionPage.prototype.unfreezeMainDiv_ = function() {
var mainDiv = this.document_.getElementById('settings_div');
if (!mainDiv.classList.contains('frozen')) {
return;
}
this.setChildNodesFocusableByTabKey_(mainDiv);
mainDiv.classList.remove('frozen');
mainDiv.style.top = '';
var scrollTop = mainDiv.oldScrollTop || 0;
mainDiv.oldScrollTop = undefined;
this.window_.scroll(0, scrollTop);
};