Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / google_input_tools / src / chrome / os / inputview / imewindows / accents.js
blob8831ca02e2128499e1c76b5b858fee79f681fdaa
1 // Copyright 2014 The ChromeOS IME Authors. All Rights Reserved.
2 // limitations under the License.
3 // See the License for the specific language governing permissions and
4 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5 // distributed under the License is distributed on an "AS-IS" BASIS,
6 // Unless required by applicable law or agreed to in writing, software
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // You may obtain a copy of the License at
11 // you may not use this file except in compliance with the License.
12 // Licensed under the Apache License, Version 2.0 (the "License");
14 goog.provide('i18n.input.chrome.inputview.Accents');
16 goog.require('goog.dom.TagName');
17 goog.require('goog.dom.classlist');
18 goog.require('goog.style');
19 goog.require('i18n.input.chrome.FloatingWindow');
20 goog.require('i18n.input.chrome.inputview.Css');
21 goog.require('i18n.input.chrome.inputview.util');
24 goog.scope(function() {
25 var Css = i18n.input.chrome.inputview.Css;
26 var FloatingWindow = i18n.input.chrome.FloatingWindow;
27 var TagName = goog.dom.TagName;
31 /**
32  * The accents floating windows.
33  *
34  * @param {!chrome.app.window.AppWindow} parentWindow The parent app window.
35  * @constructor
36  * @extends {i18n.input.chrome.FloatingWindow}
37  */
38 i18n.input.chrome.inputview.Accents = function(parentWindow) {
39   i18n.input.chrome.inputview.Accents.base(this, 'constructor',
40       parentWindow, undefined, Accents.CSS_FILE);
42 var Accents = i18n.input.chrome.inputview.Accents;
43 goog.inherits(Accents, FloatingWindow);
47 /**
48  * @const {string} The css file name for accents component.
49  */
50 Accents.CSS_FILE = 'accents_css.css'
53 /**
54  * The highlighted element.
55  *
56  * @type {Element}
57  * @private
58  */
59 Accents.prototype.highlightedItem_ = null;
62 /** @override */
63 Accents.prototype.createDom = function() {
64   Accents.base(this, 'createDom');
65   var container = this.getElement();
66   goog.dom.classlist.add(container, Css.ACCENT_CONTAINER);
67   container.id = 'container';
71 /**
72  * Gets the highlighted character.
73  *
74  * @return {string} The character.
75  */
76 Accents.prototype.getHighlightedAccent = function() {
77   return this.highlightedItem_ ?
78       this.highlightedItem_.textContent.trim() : '';
82 /**
83  * Highlights the item according to the current coordinate of the finger.
84  *
85  * @param {number} x The x position of finger in client view.
86  * @param {number} y The y position of finger in client view.
87  * @param {number} offset The offset to cancel highlight.
88  */
89 Accents.prototype.highlightItem = function(x, y, offset) {
90   var highlightedItem = this.getHighlightedItem_(x, y, offset);
91   if (this.highlightedItem_ != highlightedItem) {
92     if (this.highlightedItem_) {
93       goog.dom.classlist.remove(this.highlightedItem_, Css.ELEMENT_HIGHLIGHT);
94     }
95     this.highlightedItem_ = highlightedItem;
96     if (this.highlightedItem_ &&
97         this.highlightedItem_.textContent.trim()) {
98       goog.dom.classlist.add(this.highlightedItem_, Css.ELEMENT_HIGHLIGHT);
99     }
100   }
105  * Gets the highlighted item from |x| and |y| position.
106  * @param {number} x The x position of client View.
107  * @param {number} y The y position of client View.
108  * @param {number} offset The offset to cancel highlight.
109  * @return {Element} .
110  * @private
111  */
112 Accents.prototype.getHighlightedItem_ = function(x, y, offset) {
113   var dom = this.getDomHelper();
114   var row = null;
115   var rows = dom.getElementsByClass(Css.ACCENT_ROW);
116   for (var i = 0; i < rows.length; i++) {
117     var coordinate = goog.style.getClientPosition(rows[i]);
118     var size = goog.style.getSize(rows[i]);
119     var screenYStart = (i == 0 ? coordinate.y - offset : coordinate.y);
120     var screenYEnd = coordinate.y + size.height;
121     screenYEnd = i == rows.length - 1 ? screenYEnd + offset : screenYEnd;
122     if (screenYStart < y && screenYEnd > y) {
123       row = rows[i];
124       break;
125     }
126   }
127   if (row) {
128     var children = dom.getChildren(row);
129     for (var i = 0; i < children.length; i++) {
130       var coordinate = goog.style.getClientPosition(children[i]);
131       var size = goog.style.getSize(children[i]);
132       var screenXStart = (i == 0 ? coordinate.x - offset : coordinate.x);
133       var screenXEnd = coordinate.x + size.width;
134       screenXEnd = i == children.length - 1 ? screenXEnd + offset : screenXEnd;
135       if (screenXStart < x && screenXEnd > x) {
136         return children[i];
137       }
138     }
139   }
140   return null;
145  * Sets the accents which this window should display.
147  * @param {!Array.<string>} accents The accents to display.
148  * @param {!number} numOfColumns The number of colums of this accents window.
149  * @param {!number} numOfRows The number of rows of this accents window.
150  * @param {number} width The width of accent key.
151  * @param {number} height The height of accent key.
152  * @param {number} startKeyIndex The index of the start key in bottom row.
153  * @param {boolean} isCompact True if this accents window is for compact
154  * keyboard.
155  */
156 Accents.prototype.setAccents = function(accents, numOfColumns, numOfRows, width,
157     height, startKeyIndex, isCompact) {
158   var dom = this.getDomHelper();
159   var container = this.getElement();
160   dom.removeChildren(container);
161   var orderedAccents = this.reorderAccents_(accents, numOfColumns, numOfRows,
162       startKeyIndex);
163   var row = null;
164   for (var i = 0; i < orderedAccents.length; i++) {
165     var keyElem = dom.createDom(TagName.DIV, Css.ACCENT_KEY);
166     // Even if this is an empty key, we still need to add textDiv. Otherwise,
167     // the keys have layout issues.
168     var textDiv = dom.createElement(TagName.DIV);
169     var text = i18n.input.chrome.inputview.util.getVisibleCharacter(
170         orderedAccents[i]);
171     textDiv.textContent = text;
172     // If accent is a word use a smaller font size.
173     goog.dom.classlist.add(textDiv, text.length > 1 ? Css.FONT_SMALL :
174         (isCompact ? Css.ACCENT_COMPACT_FONT : Css.ACCENT_FULL_FONT));
176     goog.style.setStyle(textDiv, 'lineHeight', height + 'px');
177     dom.appendChild(keyElem, textDiv);
178     if (!orderedAccents[i]) {
179       goog.dom.classlist.add(keyElem, Css.ACCENT_EMPTY_KEY);
180     }
181     goog.style.setSize(keyElem, width, height);
182     if (i % numOfColumns == 0) {
183       if (row) {
184         container.appendChild(row);
185       }
186       row = dom.createDom(TagName.DIV, Css.ACCENT_ROW);
187     }
188     dom.appendChild(row, keyElem);
189   }
190   dom.appendChild(container, row);
195  * Generates the reordered accents which is optimized for creating accent key
196  * elements sequentially(from top to bottom, left to right).
197  * Accent in |accents| is ordered according to its frequency(more frequently
198  * used appears first). Once reordered, the more frequently used accents will be
199  * positioned closer to the parent key. See tests for example.
200  * @param {!Array.<string>} accents The accents to display.
201  * @param {!number} numOfColumns The number of colums of this accents window.
202  * @param {!number} numOfRows The number of rows of this accents window.
203  * @param {number} startKeyIndex The index of the start key in bottom row.
204  * @return {!Array.<string>} .
205  * @private
206  */
207 Accents.prototype.reorderAccents_ = function(accents, numOfColumns, numOfRows,
208     startKeyIndex) {
209   var orderedAccents = new Array(numOfColumns * numOfRows);
211   var index = 0;
212   // Generates the order to fill keys in a row. Start with startKeyIndex, we try
213   // to fill keys on both side(right side first) of the start key.
214   var rowOrder = new Array(numOfColumns);
215   rowOrder[startKeyIndex] = index;
216   for (var i = 1;
217       startKeyIndex + i < numOfColumns || startKeyIndex - i >= 0;
218       i++) {
219     if (startKeyIndex + i < numOfColumns) {
220       rowOrder[startKeyIndex + i] = ++index;
221     }
222     if (startKeyIndex - i >= 0) {
223       rowOrder[startKeyIndex - i] = ++index;
224     }
225   }
227   for (var i = numOfRows - 1; i >= 0; i--) {
228     for (var j = numOfColumns - 1; j >= 0; j--) {
229       index = rowOrder[j] + numOfColumns * (numOfRows - i - 1);
230       if (index >= accents.length) {
231         orderedAccents[i * numOfColumns + j] = '';
232       } else {
233         orderedAccents[i * numOfColumns + j] = accents[index];
234       }
235     }
236   }
238   return orderedAccents;
240 });  // goog.scope