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
8 // http://www.apache.org/licenses/LICENSE-2.0
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;
32 * The accents floating windows.
34 * @param {!chrome.app.window.AppWindow} parentWindow The parent app window.
36 * @extends {i18n.input.chrome.FloatingWindow}
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);
48 * @const {string} The css file name for accents component.
50 Accents.CSS_FILE = 'accents_css.css'
54 * The highlighted element.
59 Accents.prototype.highlightedItem_ = null;
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';
72 * Gets the highlighted character.
74 * @return {string} The character.
76 Accents.prototype.getHighlightedAccent = function() {
77 return this.highlightedItem_ ?
78 this.highlightedItem_.textContent.trim() : '';
83 * Highlights the item according to the current coordinate of the finger.
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.
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);
95 this.highlightedItem_ = highlightedItem;
96 if (this.highlightedItem_ &&
97 this.highlightedItem_.textContent.trim()) {
98 goog.dom.classlist.add(this.highlightedItem_, Css.ELEMENT_HIGHLIGHT);
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} .
112 Accents.prototype.getHighlightedItem_ = function(x, y, offset) {
113 var dom = this.getDomHelper();
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) {
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) {
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
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,
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(
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);
181 goog.style.setSize(keyElem, width, height);
182 if (i % numOfColumns == 0) {
184 container.appendChild(row);
186 row = dom.createDom(TagName.DIV, Css.ACCENT_ROW);
188 dom.appendChild(row, keyElem);
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>} .
207 Accents.prototype.reorderAccents_ = function(accents, numOfColumns, numOfRows,
209 var orderedAccents = new Array(numOfColumns * numOfRows);
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;
217 startKeyIndex + i < numOfColumns || startKeyIndex - i >= 0;
219 if (startKeyIndex + i < numOfColumns) {
220 rowOrder[startKeyIndex + i] = ++index;
222 if (startKeyIndex - i >= 0) {
223 rowOrder[startKeyIndex - i] = ++index;
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] = '';
233 orderedAccents[i * numOfColumns + j] = accents[index];
238 return orderedAccents;