| // 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 dictionary tool implementation. |
| * |
| * TODO(horo): Refactor the dependency to OptionPage. |
| * |
| */ |
| |
| 'use strict'; |
| |
| /** |
| * User dictionary entry item types. |
| * @const |
| * @enum {string} |
| * @private |
| */ |
| mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_ = { |
| READING: 'key', |
| WORD: 'value', |
| CATEGORY: 'pos', |
| COMMENT: 'comment' |
| }; |
| |
| /** |
| * User dictionary entry item structure information. |
| * @const |
| * @type {!Array.<!Object.<{type: mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_, |
| * divElementClass: string, |
| * inputElementClass: string, |
| * inputElementType: string}>>} |
| * @private |
| */ |
| mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_ = [ |
| { |
| type: mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_.READING, |
| divElementClass: 'dictionary_tool_reading', |
| inputElementClass: 'dictionary_tool_reading_input', |
| inputElementType: 'text' |
| }, |
| { |
| type: mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_.WORD, |
| divElementClass: 'dictionary_tool_word', |
| inputElementClass: 'dictionary_tool_word_input', |
| inputElementType: 'text' |
| }, |
| { |
| type: mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_.CATEGORY, |
| divElementClass: 'dictionary_tool_category', |
| inputElementClass: 'dictionary_tool_category_input', |
| inputElementType: 'select' |
| }, |
| { |
| type: mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_.COMMENT, |
| divElementClass: 'dictionary_tool_comment', |
| inputElementClass: 'dictionary_tool_comment_input', |
| inputElementType: 'text' |
| } |
| ]; |
| |
| /** |
| * Dictionary tool error messages. |
| * @const |
| * @type {!Object.<string, string>} |
| * @private |
| */ |
| mozc.DICTIONARY_TOOL_STATUS_ERRORS_ = { |
| 'FILE_NOT_FOUND': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorFileNotFound'), |
| 'INVALID_FILE_FORMAT': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorInvalidFileFormat'), |
| 'FILE_SIZE_LIMIT_EXCEEDED': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorFileSizeLimitExceeded'), |
| 'DICTIONARY_SIZE_LIMIT_EXCEEDED': |
| chrome.i18n.getMessage( |
| 'dictionaryToolStatusErrorDictionarySizeLimitExceeded'), |
| 'ENTRY_SIZE_LIMIT_EXCEEDED': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorEntrySizeLimitExceeded'), |
| 'DICTIONARY_NAME_EMPTY': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorDictionaryNameEmpty'), |
| 'DICTIONARY_NAME_TOO_LONG': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorDictionaryNameTooLong'), |
| 'DICTIONARY_NAME_CONTAINS_INVALID_CHARACTER': |
| chrome.i18n.getMessage( |
| 'dictionaryToolStatusErrorDictionaryNameContainsInvalidCharacter'), |
| 'DICTIONARY_NAME_DUPLICATED': |
| chrome.i18n.getMessage( |
| 'dictionaryToolStatusErrorDictionaryNameDuplicated'), |
| 'READING_EMPTY': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorReadingEmpty'), |
| 'READING_TOO_LONG': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorReadingTooLong'), |
| 'READING_CONTAINS_INVALID_CHARACTER': |
| chrome.i18n.getMessage( |
| 'dictionaryToolStatusErrorReadingContainsInvalidCharacter'), |
| 'WORD_EMPTY': chrome.i18n.getMessage('dictionaryToolStatusErrorWordEmpty'), |
| 'WORD_TOO_LONG': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorWordTooLong'), |
| 'WORD_CONTAINS_INVALID_CHARACTER': |
| chrome.i18n.getMessage( |
| 'dictionaryToolStatusErrorWordContainsInvalidCharacter'), |
| 'IMPORT_TOO_MANY_WORDS': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorImportTooManyWords'), |
| 'IMPORT_INVALID_ENTRIES': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorImportInvalidEntries'), |
| 'NO_UNDO_HISTORY': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorNoUndoHistory'), |
| 'EMPTY_FILE': |
| chrome.i18n.getMessage('dictionaryToolStatusErrorEmptyFile') |
| }; |
| |
| /** |
| * Dictionary tool error message titles. |
| * @const |
| * @type {!Object.<string, string>} |
| * @private |
| */ |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_ = { |
| CREATE_DICTIONARY: |
| chrome.i18n.getMessage('dictionaryToolStatusErrorTitleCreateDictionary'), |
| DELETE_DICTIONARY: |
| chrome.i18n.getMessage('dictionaryToolStatusErrorTitleDeleteDictionary'), |
| RENAME_DICTIONARY: |
| chrome.i18n.getMessage('dictionaryToolStatusErrorTitleRenameDictionary'), |
| EDIT_ENTRY: |
| chrome.i18n.getMessage('dictionaryToolStatusErrorTitleEditEntry'), |
| DELETE_ENTRY: |
| chrome.i18n.getMessage('dictionaryToolStatusErrorTitleDeleteEntry'), |
| ADD_ENTRY: |
| chrome.i18n.getMessage('dictionaryToolStatusErrorTitleAddEntry'), |
| IMPORT_DATA: |
| chrome.i18n.getMessage('dictionaryToolStatusErrorTitleImportData') |
| }; |
| |
| /** |
| * An empty constructor. |
| * @param {!mozc.NaclMozc} naclMozc NaCl Mozc. |
| * @param {!Window} optionWindow Window object of the option page. |
| * @param {!mozc.OptionPage} optionPage Option page object. |
| * @constructor |
| * @struct |
| * @const |
| */ |
| mozc.DictionaryTool = function(naclMozc, optionWindow, optionPage) { |
| /** |
| * 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; |
| |
| /** |
| * Option page object. |
| * @type {!mozc.OptionPage} |
| * @private |
| */ |
| this.optionPage_ = optionPage; |
| |
| /** |
| * Document object of the option page. |
| * This value will be null when the option page is unloaded. |
| * @type {Document} |
| * @private |
| */ |
| this.document_ = optionWindow.document; |
| |
| /** |
| * User dictionary session id created in NaCl module. It is set when |
| * dictionary tool is opened. |
| * @type {string} |
| * @private |
| */ |
| this.userDictionarySessionId_ = ''; |
| |
| /** |
| * Pos type list. (example: {type: 'NOUN', name: '名詞'}) |
| * @type {!Array.<!mozc.PosType>} |
| * @private |
| */ |
| this.posList_ = []; |
| |
| /** |
| * Pos type name to display name map. (example: 'NOUN' -> '名詞') |
| * @type {!Object.<string, string>} |
| * @private |
| */ |
| this.posNameMap_ = {}; |
| |
| /** |
| * Dictionary objects. |
| * @type {!Array.<!mozc.UserDictionary>} |
| * @private |
| */ |
| this.dictionaries_ = []; |
| |
| /** |
| * Selected dictionary index or NaN. |
| * @type {number} |
| * @private |
| */ |
| this.selectedDictionaryIndex_ = NaN; |
| }; |
| |
| /** |
| * Sets the pos list. |
| * @param {!Array.<!mozc.PosType>} posList pos list. |
| */ |
| mozc.DictionaryTool.prototype.setPosList = function(posList) { |
| this.posList_ = posList; |
| var new_category_select = |
| this.document_.getElementById('dictionary_tool_category_new_select'); |
| for (var i = 0; i < posList.length; ++i) { |
| this.posNameMap_[posList[i].type] = posList[i].name; |
| new_category_select.appendChild( |
| this.optionPage_.createOptionElement(posList[i].name, posList[i].type)); |
| } |
| }; |
| |
| /** |
| * Called when dictionary_tool_open_button button is clicked. |
| * This method creates a dictionary session and calls LOAD dictionary command |
| * and gets the user dictionary storage from NaCl Mozc module and shows a |
| * dictionary tool. |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolOpenButtonClicked = function() { |
| this.optionPage_.disableElementById('dictionary_tool_open_button'); |
| this.sendUserDictionaryCommand_( |
| this.createUserDictionaryCommand_('CREATE_SESSION'), |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.session_id == undefined) { |
| console.error('CREATE_SESSION error: session_id is undefined'); |
| } else { |
| this.userDictionarySessionId_ = response.session_id; |
| } |
| var command = this.createUserDictionaryCommandWithId_('LOAD'); |
| this.sendUserDictionaryCommand_( |
| command, |
| this.loadStorage_.bind( |
| this, |
| /** @this {!mozc.DictionaryTool} */ |
| (function() { |
| this.optionPage_.pushEscapeKeyHandler( |
| this.onDictionaryToolEscapeKeyPressed_.bind(this)); |
| this.optionPage_.showOverlayElementById( |
| 'dictionary_tool_overlay'); |
| this.document_.getElementById('dictionary_tool_reading_new_input') |
| .focus(); |
| }).bind(this))); |
| }).bind(this)); |
| }; |
| |
| /** |
| * Returns the name of the dictionary in the specified index. |
| * @param {number} index Index of the dictionary. |
| * @return {?string} The name of the dictionary or null when index is invalid. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.getDictionaryName_ = function(index) { |
| if (index < 0 || this.dictionaries_.length <= index) { |
| return null; |
| } |
| var dictionaryName = this.dictionaries_[index].name; |
| if (!dictionaryName) { |
| return null; |
| } |
| return dictionaryName; |
| }; |
| |
| /** |
| * Returns the dictionary index of the name. |
| * @param {string} name The name of the dictionary. |
| * @return {number} The found dictionary index or NaN |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.getDictionaryIndexByName_ = function(name) { |
| for (var i = 0; i < this.dictionaries_.length; ++i) { |
| if (this.dictionaries_[i].name == name) { |
| return i; |
| } |
| } |
| return NaN; |
| }; |
| |
| /** |
| * Updates the dictionary list in 'dictionary_tool_dictionary_list' according to |
| * dictionaries_. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.updateDictionaryList_ = function() { |
| var dictionaryList = |
| this.document_.getElementById('dictionary_tool_dictionary_list'); |
| while (dictionaryList.hasChildNodes()) { |
| dictionaryList.removeChild(dictionaryList.firstChild); |
| } |
| for (var i = 0; i < this.dictionaries_.length; ++i) { |
| var dictionaryName = this.getDictionaryName_(i) || ''; |
| var selected = this.getSelectedDictionaryIndex_() == i; |
| dictionaryList.appendChild( |
| this.createUserDictionaryListItemElement_(i, |
| dictionaryName, |
| selected)); |
| } |
| dictionaryList.appendChild(this.createUserDictionaryListNewItemElement_()); |
| }; |
| |
| /** |
| * Creates a dictionary list item like the followings. |
| * <div id="dictionary_tool_dictionary_INDEX" |
| * class="dictionary_tool_dictionary"> |
| * <div class="dictionary_tool_dictionary_name_area"> |
| * <div class="dictionary_tool_dictionary_name">DICTIONARY_NAME</div> |
| * </div> |
| * <div class="dictionary_tool_dictionary_delete_button_div"> |
| * <button class="dictionary_tool_dictionary_delete_button"></button> |
| * </div> |
| * </div> |
| * @param {number} index Index of the dictionary. |
| * @param {string} dictionaryName The name of the dictionary. |
| * @param {boolean} selected The dictionary is selected or not. |
| * @return {!Element} Created element. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.createUserDictionaryListItemElement_ = |
| function(index, dictionaryName, selected) { |
| var dictionaryDiv = this.document_.createElement('div'); |
| dictionaryDiv.id = 'dictionary_tool_dictionary_' + index; |
| dictionaryDiv.classList.add('dictionary_tool_dictionary'); |
| var dictionaryNameAreaDiv = this.document_.createElement('div'); |
| dictionaryNameAreaDiv.classList.add('dictionary_tool_dictionary_name_area'); |
| dictionaryNameAreaDiv.addEventListener( |
| 'click', |
| this.onDictionaryToolDictionaryNameAreaClicked_.bind(this, index), |
| true); |
| var dictionaryNameDiv = this.document_.createElement('div'); |
| dictionaryNameDiv.classList.add('dictionary_tool_dictionary_name'); |
| dictionaryNameDiv.appendChild( |
| this.document_.createTextNode(dictionaryName)); |
| dictionaryNameAreaDiv.appendChild(dictionaryNameDiv); |
| var dictionaryDeleteButtonDiv = this.document_.createElement('div'); |
| dictionaryDeleteButtonDiv.classList.add( |
| 'dictionary_tool_dictionary_delete_button_div'); |
| var dictionaryDeleteButton = this.document_.createElement('button'); |
| dictionaryDeleteButton.classList.add( |
| 'dictionary_tool_dictionary_delete_button'); |
| dictionaryDeleteButtonDiv.appendChild(dictionaryDeleteButton); |
| dictionaryDiv.appendChild(dictionaryNameAreaDiv); |
| dictionaryDiv.appendChild(dictionaryDeleteButtonDiv); |
| dictionaryDeleteButton.addEventListener( |
| 'click', |
| this.onDictionaryToolDictionaryDeleteButtonClicked_.bind(this, index), |
| true); |
| if (selected) { |
| dictionaryDiv.classList.add('dictionary_tool_dictionary_selected'); |
| } |
| return dictionaryDiv; |
| }; |
| |
| /** |
| * Creates a dictionary list new item element like the followings. |
| * <div class="dictionary_tool_dictionary"> |
| * <div class="dictionary_tool_dictionary_name_area"> |
| * <input class="dictionary_tool_dictionary_new_name_input" type="text"> |
| * </div> |
| * </div> |
| * @return {!Element} Created element. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.createUserDictionaryListNewItemElement_ = |
| function() { |
| var dictionaryDiv = this.document_.createElement('div'); |
| var dictionaryNameAreaDiv = this.document_.createElement('div'); |
| dictionaryNameAreaDiv.classList.add('dictionary_tool_dictionary_name_area'); |
| var inputElement = this.document_.createElement('input'); |
| inputElement.type = 'text'; |
| inputElement.classList.add('dictionary_tool_dictionary_new_name_input'); |
| inputElement.addEventListener('blur', |
| this.onDictionaryNewNameInputBlur_.bind( |
| this, inputElement), |
| true); |
| inputElement.addEventListener('keydown', |
| this.onDictionaryNewNameInputKeyDown_.bind( |
| this), |
| true); |
| inputElement.addEventListener('input', |
| this.onDictionaryNameInputChanged_.bind( |
| this, inputElement, NaN), |
| true); |
| inputElement.placeholder = |
| chrome.i18n.getMessage('dictionaryToolNewDictionaryNamePlaceholder'); |
| dictionaryNameAreaDiv.appendChild(inputElement); |
| dictionaryDiv.appendChild(dictionaryNameAreaDiv); |
| return dictionaryDiv; |
| }; |
| |
| /** |
| * Called when dictionary_tool_dictionary_new_name_input losts focus. |
| * This method creates a new dictionary. |
| * @param {!Element} inputElement The input element of the new dictionary name. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryNewNameInputBlur_ = |
| function(inputElement) { |
| var dictName = inputElement.value; |
| if (!dictName) { |
| return; |
| } |
| if (!isNaN(this.getDictionaryIndexByName_(dictName))) { |
| return; |
| } |
| var command = |
| this.createUserDictionaryCommandWithId_('CREATE_DICTIONARY'); |
| command.dictionary_name = dictName; |
| this.sendUserDictionaryCommand_( |
| command, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.status != 'USER_DICTIONARY_COMMAND_SUCCESS') { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.CREATE_DICTIONARY, |
| response.status, |
| inputElement.select.bind(inputElement)); |
| } else { |
| this.sendSaveUserDictionaryAndReloadCommand_(); |
| // TODO(horo): getStorage_ is a heavy operation. We shoud only |
| // update the created dictionary. |
| this.getStorage_(/** @this {!mozc.DictionaryTool} */ (function() { |
| this.setSelectedDictionaryIndex_(this.dictionaries_.length - 1); |
| this.updateDictionaryList_(); |
| this.updateDictionaryContent_(); |
| }).bind(this)); |
| } |
| }).bind(this)); |
| }; |
| |
| /** |
| * Called when key is down in dictionary_tool_dictionary_new_name_input. |
| * @param {Event} event Event object passed from browser. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryNewNameInputKeyDown_ = |
| function(event) { |
| if (event && event.keyCode == 13) { |
| var dictionaryList = |
| this.document_.getElementById('dictionary_tool_dictionary_list'); |
| if (dictionaryList) { |
| dictionaryList.focus(); |
| } |
| } |
| }; |
| |
| /** |
| * Called when the value of the dictionary name element is changed. This |
| * function validates the dictionary name and change the background color of the |
| * element. |
| * @param {!Element} inputElement The dictionary name input element. |
| * @param {number} index The index of the dictionary. If the dictionary name |
| * element is for the new dictionary this value is NaN. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryNameInputChanged_ = |
| function(inputElement, index) { |
| var dictName = inputElement.value; |
| var foundIndex = this.getDictionaryIndexByName_(dictName); |
| var valid = isNaN(foundIndex); |
| if (!(isNaN(index) || isNaN(foundIndex))) { |
| valid = (foundIndex == index); |
| } |
| inputElement.setCustomValidity(valid ? '' : ' '); |
| }; |
| |
| /** |
| * Gets the user dictionary storage from NaCl Mozc module and stores it to |
| * dictionaries_ and update the dictionary list and content. |
| * @param {!function()=} opt_callback Function to be called when finished. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.loadStorage_ = function(opt_callback) { |
| this.getStorage_(/** @this {!mozc.DictionaryTool} */ (function() { |
| this.updateDictionaryList_(); |
| this.updateDictionaryContent_(); |
| if (opt_callback) { |
| opt_callback(); |
| } |
| }).bind(this)); |
| }; |
| |
| /** |
| * Gets the user dictionary storage from NaCl Mozc module and stores it to |
| * dictionaries_. |
| * @param {!function()=} opt_callback Function to be called when finished. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.getStorage_ = function(opt_callback) { |
| this.sendUserDictionaryCommand_( |
| this.createUserDictionaryCommandWithId_('GET_STORAGE'), |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.storage == undefined) { |
| this.dictionaries_ = []; |
| } else { |
| this.dictionaries_ = response.storage.dictionaries; |
| } |
| if (isNaN(this.getSelectedDictionaryIndex_()) && |
| this.dictionaries_.length) { |
| this.setSelectedDictionaryIndex_(0); |
| } else { |
| this.setSelectedDictionaryIndex_(this.getSelectedDictionaryIndex_()); |
| } |
| // Sets the default values of UserDictionary. |
| for (var i = 0; i < this.dictionaries_.length; ++i) { |
| var dictionary = this.dictionaries_[i]; |
| var entries = dictionary.entries; |
| for (var j = 0; j < entries.length; ++j) { |
| var entry = entries[j]; |
| entry.key = entry.key || ''; |
| entry.value = entry.value || ''; |
| entry.pos = entry.pos || 'NOUN'; |
| entry.comment = entry.comment || ''; |
| } |
| } |
| if (opt_callback) { |
| opt_callback(); |
| } |
| }).bind(this)); |
| }; |
| |
| /** |
| * Called when the user presses Esc key while dictionary tool is opened. |
| * If the active element is INPUT element this method calls blur(), otherwise |
| * calls onDictionaryToolDoneButtonClicked(). |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolEscapeKeyPressed_ = function() { |
| if (this.document_.activeElement.tagName == 'INPUT') { |
| this.document_.activeElement.blur(); |
| return; |
| } |
| this.onDictionaryToolDoneButtonClicked(); |
| }; |
| |
| /** |
| * Called when dictionary_tool_done_button button or dictionary_tool_close |
| * button is clicked or the user presses Esc key while dictionary tool is |
| * opened and the active element is not INPUT element. |
| * This method closes the dictionary tool. |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolDoneButtonClicked = function() { |
| this.optionPage_.popEscapeKeyHandler(); |
| this.optionPage_.enableElementById('dictionary_tool_open_button'); |
| this.optionPage_.hideOverlayElementById('dictionary_tool_overlay'); |
| this.document_.getElementById('dictionary_tool_open_button').focus(); |
| }; |
| |
| /** |
| * Returns the selected dictionary index. |
| * @return {number} The selected dictionary index. The return value is NaN |
| * when there is no dictionary. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.getSelectedDictionaryIndex_ = function() { |
| return this.selectedDictionaryIndex_; |
| }; |
| |
| /** |
| * Sets the selected dictionary index. |
| * @param {number} index The selected dictionary index. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.setSelectedDictionaryIndex_ = function(index) { |
| if (isNaN(index) || this.dictionaries_.length == 0) { |
| this.selectedDictionaryIndex_ = NaN; |
| } else if (index < 0) { |
| this.selectedDictionaryIndex_ = 0; |
| } else if (index < this.dictionaries_.length) { |
| this.selectedDictionaryIndex_ = index; |
| } else { |
| this.selectedDictionaryIndex_ = this.dictionaries_.length - 1; |
| } |
| for (var i = 0; i < this.dictionaries_.length; ++i) { |
| var dictionaryDiv = |
| this.document_.getElementById('dictionary_tool_dictionary_' + i); |
| if (!dictionaryDiv) { |
| continue; |
| } |
| if (i == this.selectedDictionaryIndex_) { |
| dictionaryDiv.classList.add('dictionary_tool_dictionary_selected'); |
| } else { |
| dictionaryDiv.classList.remove('dictionary_tool_dictionary_selected'); |
| } |
| } |
| }; |
| |
| /** |
| * Key down handler of "dictionary_tool_dictionary_list" element. |
| * @param {Event} event Event object passed from browser. |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolDictionaryListKeyDown = |
| function(event) { |
| var dictIndex = this.getSelectedDictionaryIndex_(); |
| if (isNaN(dictIndex)) { |
| return; |
| } |
| if (event.keyCode == 40) { // Down |
| this.setSelectedDictionaryIndex_(dictIndex + 1); |
| } else if (event.keyCode == 38) { // Up |
| this.setSelectedDictionaryIndex_(dictIndex - 1); |
| } else if (event.keyCode == 13) { // Enter |
| this.insertDictionaryNameInputElement_(dictIndex); |
| } |
| if (dictIndex != this.getSelectedDictionaryIndex_()) { |
| this.updateDictionaryContent_(); |
| } |
| }; |
| |
| /** |
| * Called when a dictionary name area is clicked. |
| * @param {number} dictIndex The index of the clicked dictionary list item. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolDictionaryNameAreaClicked_ = |
| function(dictIndex) { |
| if (this.getSelectedDictionaryIndex_() == dictIndex) { |
| this.insertDictionaryNameInputElement_(dictIndex); |
| return; |
| } |
| this.setSelectedDictionaryIndex_(dictIndex); |
| this.updateDictionaryContent_(); |
| }; |
| |
| /** |
| * Inserts the name input element of the dictionary of the index. |
| * @param {number} index The index of the dictionary entry. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.insertDictionaryNameInputElement_ = |
| function(index) { |
| var dictionary = this.dictionaries_[index]; |
| if (!dictionary) { |
| return; |
| } |
| var dictionaryDiv = |
| this.document_.getElementById('dictionary_tool_dictionary_' + index); |
| if (!dictionaryDiv) { |
| return; |
| } |
| var nameAreaDiv = dictionaryDiv.getElementsByClassName( |
| 'dictionary_tool_dictionary_name_area')[0]; |
| if (!nameAreaDiv || |
| nameAreaDiv.classList.contains( |
| 'dictionary_tool_dictionary_name_area_selected')) { |
| return; |
| } |
| nameAreaDiv.classList.add('dictionary_tool_dictionary_name_area_selected'); |
| var inputElement = this.document_.createElement('input'); |
| inputElement.type = 'text'; |
| inputElement.classList.add('dictionary_tool_dictionary_name_input'); |
| inputElement.addEventListener('blur', |
| this.onDictionaryNameInputBlur_.bind( |
| this, |
| index, |
| inputElement, |
| dictionary.name || ''), |
| true); |
| inputElement.addEventListener('keydown', |
| this.onDictionaryNameInputKeyDown_.bind(this), |
| true); |
| inputElement.addEventListener('input', |
| this.onDictionaryNameInputChanged_.bind( |
| this, inputElement, index), |
| true); |
| inputElement.value = dictionary.name || ''; |
| nameAreaDiv.appendChild(inputElement); |
| inputElement.focus(); |
| }; |
| |
| /** |
| * Called when dictionary_tool_dictionary_name_input losts focus. |
| * @param {number} index The index of the dictionary entry. |
| * @param {!Element} inputElement The input element of the dictionary name. |
| * @param {string} originalName The original dictionary name. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryNameInputBlur_ = |
| function(index, inputElement, originalName) { |
| var newName = inputElement.value; |
| var dictionary = this.dictionaries_[index]; |
| if (!dictionary || dictionary.name != originalName) { |
| return; |
| } |
| var dictionaryDiv = |
| this.document_.getElementById('dictionary_tool_dictionary_' + index); |
| if (!dictionaryDiv) { |
| return; |
| } |
| var nameAreaDiv = dictionaryDiv.getElementsByClassName( |
| 'dictionary_tool_dictionary_name_area')[0]; |
| if (!nameAreaDiv || |
| !nameAreaDiv.classList.contains( |
| 'dictionary_tool_dictionary_name_area_selected')) { |
| return; |
| } |
| var nameDiv = nameAreaDiv.getElementsByClassName( |
| 'dictionary_tool_dictionary_name')[0]; |
| nameAreaDiv.classList.remove('dictionary_tool_dictionary_name_area_selected'); |
| nameAreaDiv.removeChild(inputElement); |
| if (!newName || !isNaN(this.getDictionaryIndexByName_(newName))) { |
| return; |
| } |
| nameDiv.innerText = newName; |
| var command = |
| this.createUserDictionaryCommandWithId_('RENAME_DICTIONARY'); |
| command.dictionary_id = dictionary.id; |
| command.dictionary_name = newName; |
| this.sendUserDictionaryCommand_( |
| command, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.status != 'USER_DICTIONARY_COMMAND_SUCCESS') { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.RENAME_DICTIONARY, |
| response.status); |
| } else { |
| this.sendSaveUserDictionaryAndReloadCommand_(); |
| dictionary.name = newName; |
| } |
| nameDiv.innerText = dictionary.name; |
| }).bind(this)); |
| }; |
| |
| /** |
| * Called when key is down in dictionary_tool_dictionary_name_input. |
| * @param {Event} event Event object passed from browser. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryNameInputKeyDown_ = function(event) { |
| if (event && event.keyCode == 13) { |
| var dictionaryList = |
| this.document_.getElementById('dictionary_tool_dictionary_list'); |
| if (dictionaryList) { |
| dictionaryList.focus(); |
| } |
| } |
| }; |
| |
| /** |
| * Called when dictionary_tool_dictionary_delete_button button is clicked. |
| * This method deletes the clicked dictionary. |
| * @param {number} dictIndex The clicked dictionary index. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolDictionaryDeleteButtonClicked_ = |
| function(dictIndex) { |
| this.optionPage_.showConfirm( |
| 'dictionary_tool_page', |
| chrome.i18n.getMessage('dictionaryToolDeleteDictionaryTitle'), |
| chrome.i18n.getMessage('dictionaryToolDeleteDictionaryConfirm', |
| this.dictionaries_[dictIndex].name || ''), |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {?boolean} result |
| */ |
| (function(result) { |
| if (!result) { |
| return; |
| } |
| var dictionaryId = this.dictionaries_[dictIndex].id; |
| var command = |
| this.createUserDictionaryCommandWithId_('DELETE_DICTIONARY'); |
| command.dictionary_id = dictionaryId; |
| this.sendUserDictionaryCommand_( |
| command, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.status != 'USER_DICTIONARY_COMMAND_SUCCESS') { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.DELETE_DICTIONARY, |
| response.status); |
| } else { |
| this.sendSaveUserDictionaryAndReloadCommand_(); |
| // TODO(horo): loadStorage_ is a heavy operation. We shoud only |
| // update the deleted dictionary. |
| this.loadStorage_(); |
| } |
| }).bind(this)); |
| }).bind(this)); |
| }; |
| |
| /** |
| * Called when export_dictionary_button button is clicked. |
| * This method exports the selecetd dictionary. |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolExportButtonClicked = function() { |
| var dictIndex = this.getSelectedDictionaryIndex_(); |
| if (isNaN(dictIndex)) { |
| return; |
| } |
| var data = ''; |
| var entries = this.dictionaries_[dictIndex].entries; |
| for (var i = 0; i < entries.length; ++i) { |
| var key = entries[i].key || ''; |
| var value = entries[i].value || ''; |
| var pos = entries[i].pos || 'NOUN'; |
| var comment = entries[i].comment || ''; |
| data += key + '\t' + |
| value + '\t' + |
| this.posNameMap_[pos] + '\t' + |
| comment + '\n'; |
| } |
| var blob = new Blob([data]); |
| var a = this.document_.createElement('a'); |
| a.href = this.window_.URL.createObjectURL(blob); |
| a.download = this.dictionaries_[dictIndex].name + '.txt'; |
| a.style.display = 'none'; |
| this.document_.body.appendChild(a); |
| a.click(); |
| this.document_.body.removeChild(a); |
| }; |
| |
| /** |
| * Called when import_dictionary_button button is clicked. |
| * This method shows "Open File" dialog using a file type input element. |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryToolImportButtonClicked = function() { |
| var fileInput = this.document_.getElementById('dictionary_import_file'); |
| if (fileInput) { |
| // To reset the files attribute of file type input element, we recreate the |
| // input element. It is needed because 'change' event will not occur if the |
| // user selects the same file twice in succession in the same input element. |
| this.document_.body.removeChild(fileInput); |
| } |
| fileInput = this.document_.createElement('input'); |
| fileInput.type = 'file'; |
| fileInput.id = 'dictionary_import_file'; |
| fileInput.style.display = 'none'; |
| fileInput.addEventListener('change', |
| this.onDictionaryImportFileChanged_.bind(this), |
| true); |
| this.document_.body.appendChild(fileInput); |
| fileInput.click(); |
| }; |
| |
| /** |
| * Returns the entry dictionary index if the element is a descendant element of |
| * a dictionary entry element. Otherwise returns NaN. |
| * @param {HTMLElement} element The descendant element of a dictionary entry |
| * element. |
| * @return {number} The entry index or NaN. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.findDictionaryEntryIndexFromElement_ = |
| function(element) { |
| if (!element) { |
| return NaN; |
| } |
| for (var elem = element; elem; elem = elem.parentElement) { |
| if (elem.classList.contains('dictionary_tool_entry')) { |
| return elem.dictionaryEntryIndex; |
| } |
| } |
| return NaN; |
| }; |
| |
| /** |
| * Returns the dictionary entry element of the index. |
| * @param {number} index The index of the dictionary entry. |
| * @return {HTMLElement} The dictionary entry element of the index or null |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.getDictionaryEntryElement_ = function(index) { |
| return this.document_.getElementById('dictionary_tool_entry_' + index); |
| }; |
| |
| /** |
| * Returns the dictionary entry sub elements of the index. |
| * @param {number} index The index of the dictionary entry. |
| * @return {Object.<mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_, !HTMLElement>} |
| * The sub elements of the specified index entry. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.getDictionaryEntrySubElements_ = function(index) { |
| var entryElem = this.getDictionaryEntryElement_(index); |
| if (!entryElem) { |
| return null; |
| } |
| var result = {}; |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| result[itemInfo.type] = |
| entryElem.getElementsByClassName(itemInfo.divElementClass)[0]; |
| } |
| return result; |
| }; |
| |
| /** |
| * Updates the dictionary entry text of the index. |
| * @param {number} index The index of the dictionary entry. |
| * @param {!mozc.UserDictionaryEntry} entry The entry data. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.updateDictionaryEntryText_ = function(index, |
| entry) { |
| var entrySubElements = this.getDictionaryEntrySubElements_(index); |
| if (!entrySubElements) { |
| return; |
| } |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| var innerText = ''; |
| if (itemInfo.type == mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_.CATEGORY) { |
| innerText = this.posNameMap_[entry[itemInfo.type]]; |
| } else { |
| innerText = entry[itemInfo.type]; |
| } |
| entrySubElements[itemInfo.type] |
| .getElementsByClassName('static_text')[0].innerText = innerText; |
| } |
| }; |
| |
| /** |
| * Sets the tab index of the dictionary entry element of the index zero to make |
| * the element focusable. |
| * @param {number} index The index of the dictionary entry. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.setDictionaryEntryZeroTabIndex_ = |
| function(index) { |
| var entrySubElements = this.getDictionaryEntrySubElements_(index); |
| if (!entrySubElements) { |
| console.error('Can\'t get the dictionary entry sub elements at ' + index); |
| return; |
| } |
| for (var key in mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_) { |
| entrySubElements[mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_[key]].tabIndex = 0; |
| } |
| }; |
| |
| /** |
| * Removes the tab index of the dictionary entry element of the index to make |
| * the element unfocusable. |
| * @param {number} index The index of the dictionary entry. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.removeDictionaryEntryTabIndex_ = function(index) { |
| var entrySubElements = this.getDictionaryEntrySubElements_(index); |
| if (!entrySubElements) { |
| console.error('Can\'t get the dictionary entry sub elements at ' + index); |
| return; |
| } |
| for (var key in mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_) { |
| entrySubElements[mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_[key]] |
| .removeAttribute('tabIndex'); |
| } |
| }; |
| |
| /** |
| * Inserts the input elements to the dictionary entry element of the index. |
| * @param {number} index The index of the dictionary entry. |
| * @param {!mozc.UserDictionaryEntry} entry The entry data. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.insertDictionaryEntryInputElements_ = |
| function(index, entry) { |
| var entrySubElements = this.getDictionaryEntrySubElements_(index); |
| if (!entrySubElements) { |
| console.error('Can\'t get the dictionary entry sub elements at ' + index); |
| return; |
| } |
| |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| var inputElement = null; |
| if (itemInfo.inputElementType == 'text') { |
| inputElement = this.document_.createElement('input'); |
| inputElement.type = 'text'; |
| } else if (itemInfo.inputElementType == 'select') { |
| inputElement = this.document_.createElement('select'); |
| } else { |
| console.error('Unsupported type: ' + itemInfo.inputElementType); |
| continue; |
| } |
| inputElement.classList.add(itemInfo.inputElementClass); |
| inputElement.addEventListener('blur', |
| this.onDictionaryEntryBlur_.bind(this), |
| true); |
| if (itemInfo.type == mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_.CATEGORY) { |
| for (var j = 0; j < this.posList_.length; ++j) { |
| inputElement.appendChild( |
| this.optionPage_.createOptionElement(this.posList_[j].name, |
| this.posList_[j].type)); |
| } |
| } |
| if (itemInfo.type == mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_.READING) { |
| inputElement.addEventListener('input', |
| this.onDictionaryReadingInputChanged.bind( |
| this, |
| inputElement), |
| true); |
| } |
| inputElement.value = entry[itemInfo.type]; |
| entrySubElements[itemInfo.type].appendChild(inputElement); |
| } |
| }; |
| |
| /** |
| * Gets the dictionary entry data from the input elements in the dictionary |
| * entry element of the index. |
| * @param {number} index The index of the dictionary entry. |
| * @return {mozc.UserDictionaryEntry} The entry data or null. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.getDictionaryEntryInputValues_ = function(index) { |
| var entryElem = this.getDictionaryEntryElement_(index); |
| if (!entryElem) { |
| return null; |
| } |
| var result = /** @type {!mozc.UserDictionaryEntry} */ ({}); |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| var inputElem = |
| entryElem.getElementsByClassName(itemInfo.inputElementClass)[0]; |
| if (!inputElem) { |
| return null; |
| } |
| result[itemInfo.type] = inputElem.value; |
| } |
| return result; |
| }; |
| |
| /** |
| * Removes the input elements in the dictionary entry element of the index. |
| * @param {number} index The index of the dictionary entry. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.removeDictionaryEntryInputElements_ = |
| function(index) { |
| var entryElem = this.getDictionaryEntryElement_(index); |
| if (!entryElem) { |
| return; |
| } |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| var inputElem = |
| entryElem.getElementsByClassName(itemInfo.inputElementClass)[0]; |
| if (inputElem) { |
| inputElem.parentElement.removeChild(inputElem); |
| } |
| } |
| }; |
| |
| /** |
| * Called when dictionary entry element is focused. |
| * This method shows the input elements for 'reading' and 'word' and 'comment', |
| * and the select element for 'category'. |
| * @param {mozc.USER_DICTIONARY_ENTRY_ITEM_TYPE_} type Entry type. |
| * @param {Event} event Event object passed from browser. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryEntryFocus_ = function(type, |
| event) { |
| if (!event) { |
| console.error('Event object is null.'); |
| return; |
| } |
| var index = this.findDictionaryEntryIndexFromElement_( |
| /** @type {HTMLElement} */ (event.target)); |
| if (isNaN(index)) { |
| console.error('Can\'t detect entry index.'); |
| return; |
| } |
| var dictIndex = this.getSelectedDictionaryIndex_(); |
| if (isNaN(dictIndex)) { |
| return; |
| } |
| var entryElem = this.getDictionaryEntryElement_(index); |
| if (!entryElem) { |
| console.error('Can\'t get dictionary entry element.'); |
| return; |
| } |
| if (entryElem.classList.contains('dictionary_tool_entry_selected')) { |
| return; |
| } |
| var entry = this.dictionaries_[dictIndex].entries[index]; |
| entryElem.classList.add('dictionary_tool_entry_selected'); |
| if (!entry) { |
| console.error('Can\'t get the entry at ' + index); |
| } else { |
| this.insertDictionaryEntryInputElements_(index, entry); |
| } |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| if (itemInfo.type == type) { |
| entryElem.getElementsByClassName(itemInfo.inputElementClass)[0].focus(); |
| } |
| } |
| this.removeDictionaryEntryTabIndex_(index); |
| }; |
| |
| /** |
| * Called when dictionary entry element lost focus. |
| * This method hides the input elements for 'reading' and 'word' and 'comment', |
| * and the select element for 'category'. And also this method saves the entry. |
| * @param {Event} event Event object passed from browser. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryEntryBlur_ = function(event) { |
| if (!event) { |
| console.error('Event object is null.'); |
| return; |
| } |
| var index = this.findDictionaryEntryIndexFromElement_( |
| /** @type {HTMLElement} */ (event.target)); |
| if (isNaN(index)) { |
| console.error('Can\'t detect entry index'); |
| return; |
| } |
| var dictIndex = this.getSelectedDictionaryIndex_(); |
| if (isNaN(dictIndex)) { |
| return; |
| } |
| if (event && event.relatedTarget && |
| this.findDictionaryEntryIndexFromElement_( |
| /** @type {HTMLElement} */ (event.relatedTarget)) == index) { |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| if (event.relatedTarget.classList.contains(itemInfo.inputElementClass)) { |
| return; |
| } |
| } |
| } |
| var entryElem = this.getDictionaryEntryElement_(index); |
| if (!entryElem) { |
| console.error('Can\'t get dictionary entry element.'); |
| return; |
| } |
| if (!entryElem.classList.contains('dictionary_tool_entry_selected')) { |
| return; |
| } |
| this.setDictionaryEntryZeroTabIndex_(index); |
| var oldEntry = this.dictionaries_[dictIndex].entries[index]; |
| var newEntry = this.getDictionaryEntryInputValues_(index); |
| entryElem.classList.remove('dictionary_tool_entry_selected'); |
| this.removeDictionaryEntryInputElements_(index); |
| if (!newEntry || |
| (newEntry.key == oldEntry.key && |
| newEntry.value == oldEntry.value && |
| newEntry.comment == oldEntry.comment && |
| newEntry.pos == oldEntry.pos)) { |
| return; |
| } |
| this.updateDictionaryEntryText_(index, newEntry); |
| var command = this.createUserDictionaryCommandWithId_('EDIT_ENTRY'); |
| command.dictionary_id = this.dictionaries_[dictIndex].id; |
| command.entry_index = [index]; |
| command.entry = newEntry; |
| this.sendUserDictionaryCommand_( |
| command, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if ((response.status != 'USER_DICTIONARY_COMMAND_SUCCESS') && |
| (response.status != 'READING_CONTAINS_INVALID_CHARACTER') && |
| (response.status != 'READING_EMPTY') && |
| (response.status != 'WORD_EMPTY')) { |
| // We ignore READING_CONTAINS_INVALID_CHARACTER, READING_EMPTY and |
| // WORD_EMPTY error to improve user experience. |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.EDIT_ENTRY, |
| response.status); |
| } |
| this.sendSaveUserDictionaryAndReloadCommand_(); |
| var command = this.createUserDictionaryCommandWithId_('GET_ENTRIES'); |
| command.dictionary_id = this.dictionaries_[dictIndex].id; |
| command.entry_index = [index]; |
| this.sendUserDictionaryCommand_( |
| command, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.entries == undefined || response.entries.length != 1) { |
| console.error('GET_ENTRIES error'); |
| return; |
| } |
| var entry = response.entries[0]; |
| this.dictionaries_[dictIndex].entries[index] = entry; |
| entry.key = entry.key || ''; |
| entry.value = entry.value || ''; |
| entry.pos = entry.pos || 'NOUN'; |
| entry.comment = entry.comment || ''; |
| this.updateDictionaryEntryText_(index, entry); |
| }).bind(this)); |
| }).bind(this)); |
| }; |
| |
| /** |
| * Called when dictionary_tool_entry_delete_button is clicked. |
| * This method deletes the entry in the dictionary. |
| * @param {Event} event Event object passed from browser. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryEntryDeleteClick_ = function(event) { |
| if (!event) { |
| console.error('Event object is null.'); |
| return; |
| } |
| var index = this.findDictionaryEntryIndexFromElement_( |
| /** @type {HTMLElement} */ (event.target)); |
| if (isNaN(index)) { |
| console.error('Can\'t detect entry index'); |
| return; |
| } |
| var dictIndex = this.getSelectedDictionaryIndex_(); |
| if (isNaN(dictIndex)) { |
| return; |
| } |
| var command = this.createUserDictionaryCommandWithId_('DELETE_ENTRY'); |
| command.dictionary_id = this.dictionaries_[dictIndex].id; |
| command.entry_index = [index]; |
| this.sendUserDictionaryCommand_( |
| command, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.status != 'USER_DICTIONARY_COMMAND_SUCCESS') { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.DELETE_ENTRY, |
| response.status); |
| this.loadStorage_(); |
| } else { |
| this.sendSaveUserDictionaryAndReloadCommand_(); |
| } |
| }).bind(this)); |
| // Removes the entry in the dictionary. |
| this.dictionaries_[dictIndex].entries.splice(index, 1); |
| // Removes the entry element of the specified index. |
| var entryElem = this.getDictionaryEntryElement_(index); |
| if (!entryElem) { |
| console.error('Can\'t get dictionary entry element.'); |
| return; |
| } |
| entryElem.parentElement.removeChild(entryElem); |
| // Changes the ID and dictionaryEntryIndex property of the following entry |
| // elements. |
| for (var i = index + 1;; ++i) { |
| entryElem = this.getDictionaryEntryElement_(i); |
| if (!entryElem) { |
| break; |
| } |
| entryElem.dictionaryEntryIndex = i - 1; |
| entryElem.id = 'dictionary_tool_entry_' + (i - 1); |
| } |
| if (this.dictionaries_[dictIndex].entries.length == 0) { |
| this.optionPage_.disableElementById('export_dictionary_button'); |
| } |
| }; |
| |
| /** |
| * Shows dictionary tool error. The dictionary tool dialog must be the active |
| * dialog when this method is called. |
| * @param {string} title The title of the dialog box. |
| * @param {string=} opt_status Status string of dictionary tool. |
| * @param {!function()=} opt_callback Function to be called when closed. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.showDictionaryToolError_ = |
| function(title, opt_status, opt_callback) { |
| var message = ''; |
| if (!opt_status) { |
| message = chrome.i18n.getMessage('dictionaryToolStatusErrorGeneral'); |
| } else { |
| message = mozc.DICTIONARY_TOOL_STATUS_ERRORS_[opt_status]; |
| if (!message) { |
| message = chrome.i18n.getMessage('dictionaryToolStatusErrorGeneral') + |
| '[' + opt_status + ']'; |
| } |
| } |
| this.optionPage_.showAlert('dictionary_tool_page', |
| title, |
| message, |
| opt_callback); |
| }; |
| |
| /** |
| * Updates the dictionary entry list in 'dictionary_tool_current_area' element |
| * according to selectedDictionaryIndex_ and dictionaries_. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.updateDictionaryContent_ = function() { |
| var dictIndex = this.getSelectedDictionaryIndex_(); |
| var currentArea = |
| this.document_.getElementById('dictionary_tool_current_area'); |
| if (isNaN(dictIndex)) { |
| for (var i = 0;; ++i) { |
| var entryElem = this.getDictionaryEntryElement_(i); |
| if (!entryElem) { |
| break; |
| } |
| currentArea.removeChild(entryElem); |
| } |
| this.optionPage_.disableElementById('export_dictionary_button'); |
| this.optionPage_.disableElementById('import_dictionary_button'); |
| this.optionPage_.disableElementById('dictionary_tool_reading_new_input'); |
| this.optionPage_.disableElementById('dictionary_tool_word_new_input'); |
| this.optionPage_.disableElementById('dictionary_tool_category_new_select'); |
| this.optionPage_.disableElementById('dictionary_tool_comment_new_input'); |
| return; |
| } |
| var dictionary = this.dictionaries_[dictIndex]; |
| if (dictionary.entries.length) { |
| this.optionPage_.enableElementById('export_dictionary_button'); |
| } else { |
| this.optionPage_.disableElementById('export_dictionary_button'); |
| } |
| this.optionPage_.enableElementById('import_dictionary_button'); |
| this.optionPage_.enableElementById('dictionary_tool_reading_new_input'); |
| this.optionPage_.enableElementById('dictionary_tool_word_new_input'); |
| this.optionPage_.enableElementById('dictionary_tool_category_new_select'); |
| this.optionPage_.enableElementById('dictionary_tool_comment_new_input'); |
| for (var i = 0; i < dictionary.entries.length; ++i) { |
| var entry = dictionary.entries[i]; |
| var entryElem = this.getDictionaryEntryElement_(i); |
| if (!entryElem) { |
| entryElem = this.createUserDictionaryEntryElement_(i); |
| } |
| currentArea.appendChild(entryElem); |
| this.updateDictionaryEntryText_(i, entry); |
| } |
| for (var i = dictionary.entries.length;; ++i) { |
| var entryElem = this.getDictionaryEntryElement_(i); |
| if (!entryElem) { |
| break; |
| } |
| currentArea.removeChild(entryElem); |
| } |
| }; |
| |
| /** |
| * Creates a dictionary entry element like the followings. And sets |
| * dictionaryEntryIndex property of dictionary_tool_entry_INDEX div to index. |
| * <div id="dictionary_tool_entry_INDEX" class="dictionary_tool_entry"> |
| * <div class="dictionary_tool_reading"> |
| * <div class="static_text"></div> |
| * </div> |
| * <div class="dictionary_tool_word"> |
| * <div class="static_text"></div> |
| * </div> |
| * <div class="dictionary_tool_category"> |
| * <div class="static_text"></div> |
| * </div> |
| * <div class="dictionary_tool_comment"> |
| * <div class="static_text"></div> |
| * </div> |
| * <div class="dictionary_tool_entry_delete_button_div"> |
| * <button class="dictionary_tool_entry_delete_button"></button> |
| * </div> |
| * </div> |
| * @param {number} index Index of the dictionary entry. |
| * @return {!Element} Created element. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.createUserDictionaryEntryElement_ = |
| function(index) { |
| var entryDiv = this.document_.createElement('div'); |
| entryDiv.id = 'dictionary_tool_entry_' + index; |
| entryDiv.classList.add('dictionary_tool_entry'); |
| // Sets dictionaryEntryIndex property to index. |
| entryDiv.dictionaryEntryIndex = index; |
| |
| for (var i = 0; i < mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_.length; ++i) { |
| var itemInfo = mozc.USER_DICTIONARY_ENTRY_ITEM_INFO_[i]; |
| var itemDiv = this.document_.createElement('div'); |
| var itemStaticDiv = this.document_.createElement('div'); |
| itemDiv.classList.add(itemInfo.divElementClass); |
| itemDiv.tabIndex = 0; |
| itemDiv.addEventListener( |
| 'focus', |
| this.onDictionaryEntryFocus_.bind(this, itemInfo.type), |
| true); |
| itemStaticDiv.classList.add('static_text'); |
| itemDiv.appendChild(itemStaticDiv); |
| entryDiv.appendChild(itemDiv); |
| } |
| |
| var deleteDiv = this.document_.createElement('div'); |
| var deleteButton = this.document_.createElement('button'); |
| deleteDiv.classList.add('dictionary_tool_entry_delete_button_div'); |
| deleteButton.classList.add('dictionary_tool_entry_delete_button'); |
| deleteButton.addEventListener( |
| 'click', |
| this.onDictionaryEntryDeleteClick_.bind(this), |
| true); |
| deleteDiv.appendChild(deleteButton); |
| entryDiv.appendChild(deleteDiv); |
| return entryDiv; |
| }; |
| |
| /** |
| * Called when the value of the reading input element is changed. This function |
| * validates the reading and change the background color of the element. |
| * @param {!Element} inputElement The reading input element. |
| * @param {Event} event Event object passed from browser. |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryReadingInputChanged = |
| function(inputElement, event) { |
| this.naclMozc_.isValidReading(inputElement.value, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.Event} response |
| */ |
| (function(response) { |
| if (inputElement.value != response.data) { |
| return; |
| } |
| inputElement.setCustomValidity(response.result ? '' : ' '); |
| }).bind(this)); |
| }; |
| |
| /** |
| * Called when dictionary tool new entry input element lost focus. |
| * If the new reading and the new word are not empty this method creates a new |
| * entry in the selected dictionary. |
| * @param {Event} event Event object passed from browser. |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryNewEntryLostFocus = function(event) { |
| if (event && event.relatedTarget && |
| (event.relatedTarget.id == 'dictionary_tool_reading_new_input' || |
| event.relatedTarget.id == 'dictionary_tool_word_new_input' || |
| event.relatedTarget.id == 'dictionary_tool_category_new_select' || |
| event.relatedTarget.id == 'dictionary_tool_comment_new_input')) { |
| return; |
| } |
| var dictIndex = this.getSelectedDictionaryIndex_(); |
| if (isNaN(dictIndex)) { |
| return; |
| } |
| var dictionaryId = this.dictionaries_[dictIndex].id; |
| var newReadingInput = |
| this.document_.getElementById('dictionary_tool_reading_new_input'); |
| var newWordInput = |
| this.document_.getElementById('dictionary_tool_word_new_input'); |
| var newCategorySelect = |
| this.document_.getElementById('dictionary_tool_category_new_select'); |
| var newCommentInput = |
| this.document_.getElementById('dictionary_tool_comment_new_input'); |
| var newReading = newReadingInput.value; |
| var newWord = newWordInput.value; |
| var newCategory = newCategorySelect.value; |
| var newComment = newCommentInput.value; |
| if (newReading == '' || newWord == '') { |
| return; |
| } |
| this.naclMozc_.isValidReading(newReading, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.Event} response |
| */ |
| (function(response) { |
| if (!response.result) { |
| return; |
| } |
| // We don't reset the value of dictionary_tool_category_new_select to |
| // help the user who want to add the same category entries. |
| newReadingInput.value = ''; |
| newWordInput.value = ''; |
| newCommentInput.value = ''; |
| var command = this.createUserDictionaryCommandWithId_('ADD_ENTRY'); |
| command.dictionary_id = dictionaryId; |
| command.entry = /** @type {!mozc.UserDictionaryEntry} */ ({ |
| 'key': newReading, |
| 'value': newWord, |
| 'comment': newComment, |
| 'pos': newCategory |
| }); |
| this.sendUserDictionaryCommand_( |
| command, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| if (response.status != 'USER_DICTIONARY_COMMAND_SUCCESS') { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.ADD_ENTRY, |
| response.status); |
| } else { |
| this.sendSaveUserDictionaryAndReloadCommand_(); |
| // TODO(horo): loadStorage_ is a heavy operation. We shoud only |
| // update the added entry. |
| this.loadStorage_(newReadingInput.focus.bind(newReadingInput)); |
| } |
| }).bind(this)); |
| }).bind(this)); |
| |
| }; |
| |
| /** |
| * Creates a mozc.UserDictionaryCommand object with the specified type and |
| * session_id. |
| * @param {string} type Input type of mozc.Command object. |
| * @return {!mozc.UserDictionaryCommand} Created mozc.UserDictionaryCommand. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.createUserDictionaryCommandWithId_ = |
| function(type) { |
| return /** @type {!mozc.UserDictionaryCommand} */ ({ |
| 'type': type, |
| 'session_id': this.userDictionarySessionId_ |
| }); |
| }; |
| |
| /** |
| * Creates a mozc.UserDictionaryCommand object with the specified type. |
| * @param {string} type Input type of mozc.Command object. |
| * @return {!mozc.UserDictionaryCommand} Created mozc.UserDictionaryCommand. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.createUserDictionaryCommand_ = |
| function(type) { |
| return /** @type {!mozc.UserDictionaryCommand} */ ({'type': type}); |
| }; |
| |
| /** |
| * Sends user dictionary command to NaCl module. |
| * @param {!mozc.UserDictionaryCommand} command User dictionary command object |
| * to be sent. |
| * @param {function(!mozc.UserDictionaryCommandStatus)=} opt_callback Function |
| * to be called with results from NaCl module. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.sendUserDictionaryCommand_ = |
| function(command, opt_callback) { |
| this.naclMozc_.sendUserDictionaryCommand(command, opt_callback); |
| }; |
| |
| /** |
| * Sends save user dictionary command and reload command to NaCl module. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.sendSaveUserDictionaryAndReloadCommand_ = |
| function() { |
| this.sendUserDictionaryCommand_( |
| this.createUserDictionaryCommandWithId_('SAVE'), |
| this.naclMozc_.sendReload.bind(this.naclMozc_, undefined)); |
| }; |
| |
| /** |
| * Returns true if charCode is non-character code. |
| * @param {number} charCode The code of a character. |
| * @return {boolean} Whether the charCode is non-character code. |
| * @see http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Noncharacters |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.isUnicodeNonCharacter_ = function(charCode) { |
| return charCode > 0xfdd0 && |
| (charCode <= 0xfdef || (charCode & 0xfffe) == 0xfffe) && |
| charCode <= 0x10ffff; |
| }; |
| |
| /** |
| * Returns true if text has non-character. |
| * @param {string} text The string to check. |
| * @return {boolean} Whether the text has non-character. |
| * @see http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Noncharacters |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.hasUnicodeNonCharacter_ = function(text) { |
| for (var i = 0; i < text.length; ++i) { |
| if (this.isUnicodeNonCharacter_(text.charCodeAt(i))) { |
| return true; |
| } |
| } |
| return false; |
| }; |
| |
| /** |
| * Called when the user selects a file to import to user dictionary. |
| * This method loads the user specified file using FileReader and sends |
| * IMPORT_DATA user dictionary command with the read data to NaCl module and |
| * closes the dictionary import dialog. |
| * @private |
| */ |
| mozc.DictionaryTool.prototype.onDictionaryImportFileChanged_ = function() { |
| var selectedDictionaryIndex = this.getSelectedDictionaryIndex_(); |
| if (isNaN(selectedDictionaryIndex)) { |
| return; |
| } |
| var fileInput = this.document_.getElementById('dictionary_import_file'); |
| var file = fileInput.files[0]; |
| var importCommand = this.createUserDictionaryCommandWithId_('IMPORT_DATA'); |
| importCommand.dictionary_id = this.dictionaries_[selectedDictionaryIndex].id; |
| var reader = new FileReader(); |
| reader.addEventListener('load', |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {Event} event |
| */ |
| (function(event) { |
| if (!event || !event.target) { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.IMPORT_DATA, |
| 'FILE_NOT_FOUND'); |
| return; |
| } else if (this.hasUnicodeNonCharacter_(event.target.result)) { |
| // NaCl module can't handle non-character. So we reject the file which |
| // contains non-character here. |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.IMPORT_DATA, |
| 'INVALID_FILE_FORMAT'); |
| return; |
| } else if (event.target.result == '') { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.IMPORT_DATA, |
| 'EMPTY_FILE'); |
| return; |
| } |
| importCommand.data = event.target.result; |
| this.sendUserDictionaryCommand_( |
| importCommand, |
| /** |
| * @this {!mozc.DictionaryTool} |
| * @param {!mozc.UserDictionaryCommandStatus} response |
| */ |
| (function(response) { |
| var importStatus = response.status; |
| this.sendSaveUserDictionaryAndReloadCommand_(); |
| this.getStorage_(/** @this {!mozc.DictionaryTool} */(function() { |
| if (selectedDictionaryIndex < 0) { |
| // Selects the last dictionary which is newly created. |
| this.setSelectedDictionaryIndex_( |
| this.dictionaries_.length - 1); |
| } else { |
| // Selects the user specified dictionary. |
| this.setSelectedDictionaryIndex_(selectedDictionaryIndex); |
| } |
| this.updateDictionaryList_(); |
| this.updateDictionaryContent_(); |
| if (importStatus != 'USER_DICTIONARY_COMMAND_SUCCESS') { |
| this.showDictionaryToolError_( |
| mozc.DICTIONARY_TOOL_STATUS_ERROR_TITLES_.IMPORT_DATA, |
| importStatus); |
| } |
| }).bind(this)); |
| }).bind(this)); |
| }).bind(this), true); |
| reader.readAsText(file); |
| }; |