• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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