1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5cr.define('options.dictionary_words', function() { 6 /** @const */ var InlineEditableItemList = options.InlineEditableItemList; 7 /** @const */ var InlineEditableItem = options.InlineEditableItem; 8 9 /** 10 * Creates a new dictionary word list item. 11 * @param {string} dictionaryWord The dictionary word. 12 * @param {function(string)} addDictionaryWordCallback Callback for 13 * adding a dictionary word. 14 * @constructor 15 * @extends {cr.ui.InlineEditableItem} 16 */ 17 function DictionaryWordsListItem(dictionaryWord, addDictionaryWordCallback) { 18 var el = cr.doc.createElement('div'); 19 el.dictionaryWord_ = dictionaryWord; 20 el.addDictionaryWordCallback_ = addDictionaryWordCallback; 21 DictionaryWordsListItem.decorate(el); 22 return el; 23 } 24 25 /** 26 * Decorates an HTML element as a dictionary word list item. 27 * @param {HTMLElement} el The element to decorate. 28 */ 29 DictionaryWordsListItem.decorate = function(el) { 30 el.__proto__ = DictionaryWordsListItem.prototype; 31 el.decorate(); 32 }; 33 34 DictionaryWordsListItem.prototype = { 35 __proto__: InlineEditableItem.prototype, 36 37 /** @override */ 38 decorate: function() { 39 InlineEditableItem.prototype.decorate.call(this); 40 if (this.dictionaryWord_ == '') 41 this.isPlaceholder = true; 42 else 43 this.editable = false; 44 45 var wordEl = this.createEditableTextCell(this.dictionaryWord_); 46 wordEl.classList.add('weakrtl'); 47 wordEl.classList.add('language-dictionary-overlay-word-list-item'); 48 this.contentElement.appendChild(wordEl); 49 50 var wordField = wordEl.querySelector('input'); 51 wordField.classList.add('language-dictionary-overlay-word-list-item'); 52 if (this.isPlaceholder) { 53 wordField.placeholder = 54 loadTimeData.getString('languageDictionaryOverlayAddWordLabel'); 55 } 56 57 this.addEventListener('commitedit', this.onEditCommitted_.bind(this)); 58 }, 59 60 /** @override */ 61 get hasBeenEdited() { 62 return this.querySelector('input').value.length > 0; 63 }, 64 65 /** 66 * Adds a word to the dictionary. 67 * @param {Event} e Edit committed event. 68 * @private 69 */ 70 onEditCommitted_: function(e) { 71 var input = e.currentTarget.querySelector('input'); 72 this.addDictionaryWordCallback_(input.value); 73 input.value = ''; 74 }, 75 }; 76 77 /** 78 * A list of words in the dictionary. 79 * @extends {cr.ui.InlineEditableItemList} 80 */ 81 var DictionaryWordsList = cr.ui.define('list'); 82 83 DictionaryWordsList.prototype = { 84 __proto__: InlineEditableItemList.prototype, 85 86 /** 87 * The function to notify that the word list has changed. 88 * @type {function()} 89 */ 90 onWordListChanged: null, 91 92 /** 93 * The list of all words in the dictionary. Used to generate a filtered word 94 * list in the |search(searchTerm)| method. 95 * @type {Array} 96 * @private 97 */ 98 allWordsList_: null, 99 100 /** 101 * The list of words that the user removed, but |DictionaryWordList| has not 102 * received a notification of their removal yet. 103 * @type {Array} 104 * @private 105 */ 106 removedWordsList_: [], 107 108 /** 109 * Adds a dictionary word. 110 * @param {string} dictionaryWord The word to add. 111 * @private 112 */ 113 addDictionaryWord_: function(dictionaryWord) { 114 this.allWordsList_.push(dictionaryWord); 115 this.dataModel.splice(this.dataModel.length - 1, 0, dictionaryWord); 116 this.onWordListChanged(); 117 chrome.send('addDictionaryWord', [dictionaryWord]); 118 }, 119 120 /** 121 * Searches the list for the matching words. 122 * @param {string} searchTerm The search term. 123 */ 124 search: function(searchTerm) { 125 var filteredWordList = this.allWordsList_.filter( 126 function(element, index, array) { 127 return element.indexOf(searchTerm) > -1; 128 }); 129 filteredWordList.push(''); 130 this.dataModel = new cr.ui.ArrayDataModel(filteredWordList); 131 this.onWordListChanged(); 132 }, 133 134 /** 135 * Sets the list of dictionary words. 136 * @param {Array} entries The list of dictionary words. 137 */ 138 setWordList: function(entries) { 139 this.allWordsList_ = entries.slice(0); 140 // Empty string is a placeholder for entering new words. 141 entries.push(''); 142 this.dataModel = new cr.ui.ArrayDataModel(entries); 143 this.onWordListChanged(); 144 }, 145 146 /** 147 * Adds non-duplicate dictionary words. 148 * @param {Array} entries The list of dictionary words. 149 */ 150 addWords: function(entries) { 151 var toAdd = []; 152 for (var i = 0; i < entries.length; i++) { 153 if (this.allWordsList_.indexOf(entries[i]) == -1) { 154 this.allWordsList_.push(entries[i]); 155 toAdd.push(entries[i]); 156 } 157 } 158 if (toAdd.length == 0) 159 return; 160 for (var i = 0; i < toAdd.length; i++) 161 this.dataModel.splice(this.dataModel.length - 1, 0, toAdd[i]); 162 this.onWordListChanged(); 163 }, 164 165 /** 166 * Removes dictionary words that are not in |removedWordsList_|. If a word 167 * is in |removedWordsList_|, then removes the word from there instead. 168 * @param {Array} entries The list of dictionary words. 169 */ 170 removeWords: function(entries) { 171 var index; 172 var toRemove = []; 173 for (var i = 0; i < entries.length; i++) { 174 index = this.removedWordsList_.indexOf(entries[i]); 175 if (index > -1) { 176 this.removedWordsList_.splice(index, 1); 177 } else { 178 index = this.allWordsList_.indexOf(entries[i]); 179 if (index > -1) { 180 this.allWordsList_.splice(index, 1); 181 toRemove.push(entries[i]); 182 } 183 } 184 } 185 if (toRemove.length == 0) 186 return; 187 for (var i = 0; i < toRemove.length; i++) { 188 index = this.dataModel.indexOf(toRemove[i]); 189 if (index > -1) 190 this.dataModel.splice(index, 1); 191 } 192 this.onWordListChanged(); 193 }, 194 195 /** 196 * Returns true if the data model contains no words, otherwise returns 197 * false. 198 * @type {boolean} 199 */ 200 get empty() { 201 // A data model without dictionary words contains one placeholder for 202 // entering new words. 203 return this.dataModel.length < 2; 204 }, 205 206 /** @override */ 207 createItem: function(dictionaryWord) { 208 return new DictionaryWordsListItem( 209 dictionaryWord, 210 this.addDictionaryWord_.bind(this)); 211 }, 212 213 /** @override */ 214 deleteItemAtIndex: function(index) { 215 // The last element in the data model is an undeletable placeholder for 216 // entering new words. 217 assert(index > -1 && index < this.dataModel.length - 1); 218 var item = this.dataModel.item(index); 219 var allWordsListIndex = this.allWordsList_.indexOf(item); 220 assert(allWordsListIndex > -1); 221 this.allWordsList_.splice(allWordsListIndex, 1); 222 this.dataModel.splice(index, 1); 223 this.removedWordsList_.push(item); 224 this.onWordListChanged(); 225 chrome.send('removeDictionaryWord', [item]); 226 }, 227 228 /** @override */ 229 shouldFocusPlaceholder: function() { 230 return false; 231 }, 232 }; 233 234 return { 235 DictionaryWordsList: DictionaryWordsList 236 }; 237 238}); 239 240