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
);