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.util');
16 goog.require('goog.string');
17 goog.require('goog.style');
20 goog.scope(function() {
21 var util = i18n.input.chrome.inputview.util;
25 * The mapping between the real character and its replacement for display.
27 * @type {!Object.<string, string>}
29 util.DISPLAY_MAPPING = {
48 '\u030F' : '\u030F\u0020',
49 '\u031B' : '\u031B\u0020',
50 '\u0323' : '\u0323\u0020'
55 * The keysets using US keyboard layouts.
57 * @type {!Array.<string>}
59 util.KEYSETS_USE_US = [
73 * The keysets that have en switcher key.
75 * @type {!Array.<string>}
77 util.KEYSETS_HAVE_EN_SWTICHER = [
78 // When other keysets that use us add the enswitcher key,
79 // should move them to this array.
92 * The keysets that have compact keyset.
94 * @type {!Array.<string>}
96 util.KEYSETS_HAVE_COMPACT = [
116 * A regular expression for the end of a sentence.
120 util.END_SENTENCE_REGEX_ = /[\.\?!] +$/;
124 * The regex of characters support dead key.
129 util.REGEX_CHARACTER_SUPPORT_DEADKEY_ =
130 /^[a-zA-ZæÆœŒΑΕΗΙΟΥΩαεηιυοωϒ]+$/;
134 * The regex of characters supported in language module.
138 util.REGEX_LANGUAGE_MODEL_CHARACTERS =
139 /(?=[^\u00d7\u00f7])[a-z\-\'\u00c0-\u017F]/i;
143 * Splits a value to pieces according to the weights.
145 * @param {!Array.<number>} weightArray The weight array.
146 * @param {number} totalValue The total value.
147 * @return {!Array.<number>} The splitted values.
149 util.splitValue = function(weightArray, totalValue) {
150 if (weightArray.length == 0) {
154 if (weightArray.length == 1) {
159 for (var i = 0; i < weightArray.length; i++) {
160 totalWeight += weightArray[i];
162 var tmp = totalValue / totalWeight;
164 var totalFlooredValue = 0;
166 for (var i = 0; i < weightArray.length; i++) {
167 var result = weightArray[i] * tmp;
169 diffs.push(result - Math.floor(result));
170 totalFlooredValue += Math.floor(result);
172 var diff = totalValue - totalFlooredValue;
174 // Distributes the rest pixels to values who lose most.
175 for (var i = 0; i < diff; i++) {
178 for (var j = 0; j < diffs.length; j++) {
179 if (diffs[j] > max) {
187 for (var i = 0; i < values.length; i++) {
188 values[i] = Math.floor(values[i]);
195 * Gets the value of a property.
197 * @param {Element} elem The element.
198 * @param {string} property The property name.
199 * @return {number} The value.
201 util.getPropertyValue = function(elem, property) {
202 var value = goog.style.getComputedStyle(elem, property);
204 return parseInt(value.replace('px', ''), 10);
213 * @param {string} character The character.
214 * @return {string} The uppercase of the character.
216 util.toUpper = function(character) {
217 if (character == '\u00b5') {
220 return character.toUpperCase();
228 * @param {string} character The character.
229 * @return {string} The lower case of the character.
231 util.toLower = function(character) {
232 if (character == '\u0049') {
235 return character.toLowerCase();
240 * Is this character trigger commit.
242 * @param {string} character The character.
243 * @return {boolean} True to trigger commit.
245 util.isCommitCharacter = function(character) {
246 if (util.DISPLAY_MAPPING[character] ||
247 util.REGEX_LANGUAGE_MODEL_CHARACTERS.test(
257 * Some unicode character can't be shown in the web page, use a replacement
260 * @param {string} invisibleCharacter The character can't be shown.
261 * @return {string} The replacement.
263 util.getVisibleCharacter = function(invisibleCharacter) {
264 var map = util.DISPLAY_MAPPING;
265 if (map[invisibleCharacter]) {
266 return map[invisibleCharacter];
268 // For non-spacing marks (e.g. \u05b1), ChromeOS cannot display it correctly
269 // until there is a character before it to combine with.
270 if (/[\u0591-\u05cf]/.test(invisibleCharacter)) {
271 return '\u00a0' + invisibleCharacter;
273 return invisibleCharacter;
278 * Whether this is a letter key.
280 * @param {!Array.<string>} characters The characters.
281 * @return {boolean} True if this is a letter key.
283 util.isLetterKey = function(characters) {
284 if (characters[1] == util.toUpper(
285 characters[0]) || characters[1] == util.
286 toLower(characters[0])) {
294 * True if this character supports dead key combination.
296 * @param {string} character The character.
297 * @return {boolean} True if supports the dead key combination.
299 util.supportDeadKey = function(character) {
300 return util.REGEX_CHARACTER_SUPPORT_DEADKEY_.
306 * True if we need to do the auto-capitalize.
308 * @param {string} text .
309 * @return {boolean} .
311 util.needAutoCap = function(text) {
312 if (goog.string.isEmptyOrWhitespace(text)) {
315 return util.END_SENTENCE_REGEX_.test(text);
321 * Returns the configuration file name from the keyboard code.
323 * @param {string} keyboardCode The keyboard code.
324 * @return {string} The config file name which contains the keyset.
326 util.getConfigName = function(keyboardCode) {
327 // Strips out all the suffixes in the keyboard code.
328 return keyboardCode.replace(/\..*$/, '');
333 * Checks that the word is a valid delete from the old to new context.
335 * @param {string} oldContext The old context.
336 * @param {string} newContext The new context.
337 * @param {string} deletionCandidate A possible word deletion.
339 * @return {boolean} Whether the deletion was valid.
341 util.isPossibleDelete = function(
342 oldContext, newContext, deletionCandidate) {
343 // Check that deletionCandidate exists in oldContext. We don't check if it's a
344 // tail since our heuristic may have trimmed whitespace.
345 var rootEnd = oldContext.lastIndexOf(deletionCandidate);
347 // Check that remaining text in root persisted in newContext.
348 var root = oldContext.slice(0, rootEnd);
349 return root == newContext.slice(-rootEnd);
356 * Checks whether a letter deletion would cause the observed context transform.
358 * @param {string} oldContext The old context.
359 * @param {string} newContext The new context.
361 * @return {boolean} Whether the transform is valid.
363 util.isLetterDelete = function(oldContext, newContext) {
364 if (oldContext == '') {
367 // Handle buffer overflow.
368 if (oldContext.length == newContext.length) {
369 return util.isLetterDelete(oldContext, newContext.slice(1));
371 return oldContext.length == newContext.length + 1 &&
372 oldContext.indexOf(newContext) == 0;
377 * Checks whether a letter restoration would cause the observed context
380 * @param {string} oldContext The old context.
381 * @param {string} newContext The new context.
383 * @return {boolean} Whether the transform is valid.
385 util.isLetterRestore = function(oldContext, newContext) {
386 return util.isLetterDelete(newContext, oldContext);