ApplicationImpl cleanup, part 1:
[chromium-blink-merge.git] / third_party / google_input_tools / src / chrome / os / inputview / inputtool.js
blob1ab0845ef14df1028f440f3cd011e9025a240d01
1 // Copyright 2013 Google Inc. All Rights Reserved.
3 /**
4 * @fileoverview This file defines the input tool, included IME and virtual
5 * keyboard.
7 * @author wuyingbing@google.com (Yingbing Wu)
8 */
10 goog.provide('i18n.input.lang.InputTool');
12 goog.require('goog.array');
13 goog.require('goog.object');
14 goog.require('goog.string');
15 goog.require('i18n.input.common.GlobalSettings');
16 goog.require('i18n.input.lang.InputToolCode');
17 goog.require('i18n.input.lang.InputToolType');
19 goog.scope(function() {
20 var GlobalSettings = i18n.input.common.GlobalSettings;
21 var InputToolCode = i18n.input.lang.InputToolCode;
22 var InputToolType = i18n.input.lang.InputToolType;
26 /**
27 * The input tool class is used to define Input Tool. Don't call the method
28 * directly, use InputTool.get instead.
30 * @param {!InputToolCode} inputToolCode The input tool code
31 * value.
32 * @constructor
34 i18n.input.lang.InputTool = function(inputToolCode) {
35 /**
36 * The unique code of input tools.
38 * @type {!InputToolCode}
40 this.code = inputToolCode;
42 /**
43 * The input tools type value.
45 * @type {?InputToolType}
47 this.type = null;
49 /**
50 * The target language code.
52 * @type {string}
54 this.languageCode = 'en';
56 /**
57 * The source language code.
59 * @type {string}
61 this.sourceLanguageCode = 'en';
63 /**
64 * Keyboard layout code. Only valid if type is KBD.
65 * @type {string}
67 this.layoutCode;
69 // Parses input tool code.
70 this.parseInputToolCode_();
72 var InputTool = i18n.input.lang.InputTool;
75 /**
76 * The array of rtl keyboards' input tool codes.
78 * @type {!Array.<string>}
80 InputTool.RtlKeyboards = [
81 InputToolCode.KEYBOARD_ARABIC,
82 InputToolCode.KEYBOARD_DARI,
83 InputToolCode.KEYBOARD_HEBREW,
84 InputToolCode.KEYBOARD_PASHTO,
85 InputToolCode.KEYBOARD_PERSIAN,
86 InputToolCode.KEYBOARD_SOUTHERN_UZBEK,
87 InputToolCode.KEYBOARD_UIGHUR,
88 InputToolCode.KEYBOARD_URDU,
89 InputToolCode.KEYBOARD_YIDDISH];
92 /**
93 * The array of rtl ime' input tool codes.
95 * @type {!Array.<string>}
97 InputTool.RtlIMEs = [
98 InputToolCode.INPUTMETHOD_TRANSLITERATION_ARABIC,
99 InputToolCode.INPUTMETHOD_TRANSLITERATION_HEBREW,
100 InputToolCode.INPUTMETHOD_TRANSLITERATION_PERSIAN,
101 InputToolCode.INPUTMETHOD_TRANSLITERATION_URDU];
105 * The mapping from 3-letter language codes to 2-letter language codes.
107 * @type {!Object.<string, string>}
109 InputTool.LanguageCodeThreeTwoMap = goog.object.create(
110 'arm', 'hy',
111 'bel', 'be',
112 'bul', 'bg',
113 'cat', 'ca',
114 'cze', 'cs',
115 'dan', 'da',
116 'eng', 'en',
117 'est', 'et',
118 'fin', 'fi',
119 'fra', 'fr',
120 'geo', 'ka',
121 'ger', 'de',
122 'gre', 'el',
123 'heb', 'he',
124 'hun', 'hu',
125 'ice', 'is',
126 'ind', 'id',
127 'ita', 'it',
128 'jpn', 'ja',
129 'lav', 'lv',
130 'lit', 'lt',
131 'mlt', 'mt',
132 'mon', 'mn',
133 'msa', 'ms',
134 'nld', 'nl',
135 // The new specification is "nb", but NACL uses "no".
136 'nob', 'no',
137 'pol', 'pl',
138 'por', 'pt',
139 'rum', 'ro',
140 'rus', 'ru',
141 'scr', 'hr',
142 'slo', 'sk',
143 'slv', 'sl',
144 'spa', 'es',
145 'srp', 'sr',
146 'swe', 'sv',
147 'tur', 'tr',
148 'ukr', 'uk');
152 * The special XKB id to language code mapping.
154 * @private {!Object.<string, string>}
156 InputTool.XkbId2Language_ = {
157 // NACL treads "pt-BR", "pt-PT" the same with "pt".
158 'xkb:us:intl:por': 'pt',
159 'xkb:br::por': 'pt',
160 'xkb:pt::por': 'pt'
165 * The input tool code and instance mapping.
167 * @type {!Object.<string, InputTool>}
168 * @private
170 InputTool.instances_ = {};
174 * Gets an input tool by code.
176 * @param {!string} inputToolCode The input tool code value.
177 * @return {InputTool} The input tool.
179 InputTool.get = function(inputToolCode) {
180 if (!inputToolCode) {
181 return null;
184 // The code isn't BCP47 pattern, transfers it from old pattern.
185 if (!goog.object.contains(InputToolCode, inputToolCode)) {
186 inputToolCode = InputTool.parseToBCP47_(inputToolCode);
189 // Allow BCP47 code 'fa_t_k0_und' to 'fa-t-k0-und'.
190 inputToolCode = inputToolCode.replace(/_/g, '-');
192 // Adds '-und' to keep compatible with previous codes.
193 if (!goog.object.contains(InputToolCode, inputToolCode)) {
194 inputToolCode = InputTool.parseToBCP47_(
195 inputToolCode + '-und');
198 if (InputTool.instances_[inputToolCode]) {
199 return InputTool.instances_[inputToolCode];
202 // If the input tool code is valid.
203 if (goog.object.contains(InputToolCode, inputToolCode)) {
204 InputTool.instances_[inputToolCode] =
205 new InputTool(
206 /** @type {InputToolCode} */ (inputToolCode));
207 return InputTool.instances_[inputToolCode];
210 return null;
215 * Language codes whose BCP47 code has a rule like:
216 * Has 'und-latn', then adding 'phone' at last, otherwise, 'inscript' at last.
218 * @type {!Array.<string>}
219 * @private
221 InputTool.PHONETIC_INSCRIPT_LANGS_ = [
222 'bn', 'gu', 'pa', 'kn', 'ml', 'or', 'sa', 'ta', 'te', 'ne'
227 * Special previous old code mapping to BCP47 code.
229 * @type {!Object.<string, string>}
230 * @private
231 * @const
233 InputTool.BCP47_SPECIAL_ = {
234 'im_pinyin_zh_hans': InputToolCode.INPUTMETHOD_PINYIN_CHINESE_SIMPLIFIED,
235 'im_pinyin_zh_hant': InputToolCode.INPUTMETHOD_PINYIN_CHINESE_TRADITIONAL,
236 'im_t13n_ja': InputToolCode.INPUTMETHOD_TRANSLITERATION_JAPANESE,
237 'im_t13n_ja-Hira': InputToolCode.INPUTMETHOD_TRANSLITERATION_HIRAGANA,
238 'im_wubi_zh_hans': InputToolCode.INPUTMETHOD_WUBI_CHINESE_SIMPLIFIED,
239 'im_zhuyin_zh_hant': InputToolCode.INPUTMETHOD_ZHUYIN_CHINESE_TRADITIONAL,
240 'vkd_bg_phone': InputToolCode.KEYBOARD_BULGARIAN_PHONETIC,
241 'vkd_chr_phone': InputToolCode.KEYBOARD_CHEROKEE_PHONETIC,
242 'vkd_cs_qwertz': InputToolCode.KEYBOARD_CZECH_QWERTZ,
243 'vkd_deva_phone': InputToolCode.KEYBOARD_DEVANAGARI_PHONETIC,
244 'vkd_en_dvorak': InputToolCode.KEYBOARD_ENGLISH_DVORAK,
245 'vkd_es_es': InputToolCode.KEYBOARD_SPANISH,
246 'vkd_ethi': InputToolCode.KEYBOARD_ETHIOPIC,
247 'vkd_gu_phone': InputToolCode.KEYBOARD_GUJARATI_PHONETIC,
248 'vkd_guru_inscript': InputToolCode.KEYBOARD_GURMUKHI_INSCRIPT,
249 'vkd_guru_phone': InputToolCode.KEYBOARD_GURMUKHI_PHONETIC,
250 'vkd_hu_101': InputToolCode.KEYBOARD_HUNGARIAN_101,
251 'vkd_hy_east': InputToolCode.KEYBOARD_ARMENIAN_EASTERN,
252 'vkd_hy_west': InputToolCode.KEYBOARD_ARMENIAN_WESTERN,
253 'vkd_ka_qwerty': InputToolCode.KEYBOARD_GEORGIAN_QWERTY,
254 'vkd_ka_typewriter': InputToolCode.KEYBOARD_GEORGIAN_TYPEWRITER,
255 'vkd_ro_sr13392_primary': InputToolCode.KEYBOARD_ROMANIAN_SR13392_PRIMARY,
256 'vkd_ro_sr13392_secondary': InputToolCode.KEYBOARD_ROMANIAN_SR13392_SECONDARY,
257 'vkd_ru_phone': InputToolCode.KEYBOARD_RUSSIAN_PHONETIC,
258 'vkd_ru_phone_aatseel': InputToolCode.KEYBOARD_RUSSIAN_PHONETIC_AATSEEL,
259 'vkd_ru_phone_yazhert': InputToolCode.KEYBOARD_RUSSIAN_PHONETIC_YAZHERT,
260 'vkd_sk_qwerty': InputToolCode.KEYBOARD_SLOVAK_QWERTY,
261 'vkd_ta_itrans': InputToolCode.KEYBOARD_TAMIL_ITRANS,
262 'vkd_ta_tamil99': InputToolCode.KEYBOARD_TAMIL_99,
263 'vkd_ta_typewriter': InputToolCode.KEYBOARD_TAMIL_TYPEWRITER,
264 'vkd_th_pattajoti': InputToolCode.KEYBOARD_THAI_PATTAJOTI,
265 'vkd_th_tis': InputToolCode.KEYBOARD_THAI_TIS,
266 'vkd_tr_f': InputToolCode.KEYBOARD_TURKISH_F,
267 'vkd_tr_q': InputToolCode.KEYBOARD_TURKISH_Q,
268 'vkd_uk_101': InputToolCode.KEYBOARD_UKRAINIAN_101,
269 'vkd_us_intl': InputToolCode.KEYBOARD_FRENCH_INTL,
270 'vkd_uz_cyrl_phone': InputToolCode.KEYBOARD_UZBEK_CYRILLIC_PHONETIC,
271 'vkd_uz_cyrl_type': InputToolCode.KEYBOARD_UZBEK_CYRILLIC_TYPEWRITTER,
272 'vkd_vi_tcvn': InputToolCode.KEYBOARD_VIETNAMESE_TCVN,
273 'vkd_vi_telex': InputToolCode.KEYBOARD_VIETNAMESE_TELEX
278 * BCP47 code maps to previous code.
280 * @type {!Object.<string, string>}
281 * @private
283 InputTool.BCP47_SPECIAL_REVERSE_ = goog.object.transpose(
284 InputTool.BCP47_SPECIAL_);
288 * Special keyboard layout code mapping. Multiple Input Tools map to the same
289 * layout.
291 * key: Input Tool code.
292 * value: layout code.
294 * @private {!Object.<string, string>}
296 InputTool.SpecialLayoutCodes_ = goog.object.create(
297 InputToolCode.KEYBOARD_DUTCH_INTL, 'us_intl',
298 InputToolCode.KEYBOARD_FRENCH_INTL, 'us_intl',
299 InputToolCode.KEYBOARD_GERMAN_INTL, 'us_intl',
300 InputToolCode.KEYBOARD_HAITIAN, 'fr',
301 InputToolCode.KEYBOARD_INDONESIAN, 'latn_002',
302 InputToolCode.KEYBOARD_IRISH, 'latn_002',
303 InputToolCode.KEYBOARD_ITALIAN_INTL, 'us_intl',
304 InputToolCode.KEYBOARD_JAVANESE, 'latn_002',
305 InputToolCode.KEYBOARD_MARATHI, 'deva_phone',
306 InputToolCode.KEYBOARD_MALAY, 'latn_002',
307 InputToolCode.KEYBOARD_PORTUGUESE_BRAZIL_INTL, 'us_intl',
308 InputToolCode.KEYBOARD_PORTUGUESE_PORTUGAL_INTL, 'us_intl',
309 InputToolCode.KEYBOARD_SPANISH_INTL, 'us_intl',
310 InputToolCode.KEYBOARD_SWAHILI, 'latn_002',
311 InputToolCode.KEYBOARD_TAGALOG, 'latn_002',
312 InputToolCode.KEYBOARD_TIGRINYA, 'ethi',
313 InputToolCode.KEYBOARD_WELSH, 'latn_002');
317 * Parses previous old code to BCP 47 code.
319 * @param {string} itCode Previous old input tool code format.
320 * @return {string} BCP 47 code.
321 * @private
323 InputTool.parseToBCP47_ = function(itCode) {
324 if (InputTool.BCP47_SPECIAL_[itCode]) {
325 return InputTool.BCP47_SPECIAL_[itCode];
328 if (itCode == 'vkd_iw') {
329 return InputToolCode.KEYBOARD_HEBREW;
332 if (itCode == 'im_t13n_iw') {
333 return InputToolCode.INPUTMETHOD_TRANSLITERATION_HEBREW;
336 // Types 'legacy' to 'lagacy' by mistake, correct it.
337 // Can't put 'tr' + '-t-k0-lagacy' into BCP47_SPECIAL_ map, becasue we have
338 // to split 'tr-t-k0-lagacy' but JS grammar wasn't allow to
339 // use 'tr' + '-t-k0-lagacy' as key.
340 if (itCode == 'tr' + '-t-k0-lagacy') {
341 return InputToolCode.KEYBOARD_TURKISH_F;
344 var parts = itCode.split('_');
345 var code = '';
346 if (goog.string.startsWith(itCode, 'im_t13n')) {
347 // Example: 'im_t13n_hi'.
348 code = parts[2] + '-t-i0-und';
349 } else if (goog.string.startsWith(itCode, 'vkd_')) {
350 // Special codes for keyboard.
351 if (parts.length == 2) {
352 // Example: 'vkd_sq'
353 code = parts[1] + '-t-k0-und';
354 } else {
355 if (goog.array.contains(
356 InputTool.PHONETIC_INSCRIPT_LANGS_, parts[1])) {
357 if (parts[2] == 'inscript') {
358 code = parts[1] + '-t-k0-und';
359 } else {
360 code = parts[1] + '-t-und-latn-k0-und';
362 } else {
363 code = parts[1] + '-t-k0-' + parts[2];
364 if (!goog.object.contains(InputToolCode, code)) {
365 code = parts[1] + '-' + parts[2] + '-t-k0-und';
370 return goog.object.contains(InputToolCode, code) ? code : itCode;
375 * Gets the input tools by parameters. Keep compatible with previous language
376 * code pair. Not support to get input tool by keyboard layout.
378 * @param {!InputToolType} type The input tool type.
379 * @param {!string} code It's the target language code if type is input method.
380 * @return {InputTool} The input tool.
382 InputTool.getInputTool = function(type, code) {
383 // Makes compatible input tool code with previous language code version.
384 if (type == InputToolType.IME) {
385 if (code == 'zh' || code == 'zh-Hans') {
386 return InputTool.get(
387 InputToolCode.INPUTMETHOD_PINYIN_CHINESE_SIMPLIFIED);
388 } else if (code == 'zh-Hant') {
389 return InputTool.get(
390 InputToolCode.INPUTMETHOD_ZHUYIN_CHINESE_TRADITIONAL);
391 } else if (code == 'ja') {
392 return InputTool.get(
393 InputToolCode.INPUTMETHOD_TRANSLITERATION_JAPANESE);
394 } else {
395 return InputTool.get(code + '-t-i0-und');
397 } else if (type == InputToolType.KBD) {
398 return InputTool.get('vkd_' + code);
400 return null;
405 * Parses BCP47 codes to the virtual keyboard layout.
407 * @private
409 InputTool.prototype.parseLayoutCode_ = function() {
410 if (InputTool.SpecialLayoutCodes_[this.code]) {
411 this.layoutCode = InputTool.SpecialLayoutCodes_[this.code];
412 } else if (InputTool.BCP47_SPECIAL_REVERSE_[this.code]) {
413 // Removes prefix 'vkd_';
414 this.layoutCode = InputTool.
415 BCP47_SPECIAL_REVERSE_[this.code].slice(4);
416 } else {
417 var parts = this.code.split('-t-');
418 var countryCode = parts[0];
419 var inputToolType = parts[1];
420 countryCode = countryCode.replace(/-/g, '_');
421 if (countryCode == 'en_us') {
422 countryCode = 'us';
425 if (goog.array.contains(
426 InputTool.PHONETIC_INSCRIPT_LANGS_, countryCode) &&
427 (inputToolType == 'und-latn-k0-und' || inputToolType == 'k0-und')) {
428 // If it's virtual keyboard having the inscript/phonetic rule.
429 this.layoutCode = countryCode +
430 (inputToolType == 'k0-und' ? '_inscript' : '_phone');
431 } else if (inputToolType == 'k0-und') {
432 this.layoutCode = countryCode;
433 } else {
434 var matches = inputToolType.match(/k0-(.*)/);
435 if (matches[1]) {
436 this.layoutCode = countryCode + '_' + matches[1].replace(
437 'qwerty', 'phone');
445 * Parses the input tool code.
446 * TODO(wuyingbing): We will introduce new code pattern, and then write a new
447 * parsing method.
449 * @private
451 InputTool.prototype.parseInputToolCode_ = function() {
452 // Sets the input tool type.
453 if (this.code.indexOf('-i0') >= 0) {
454 this.type = InputToolType.IME;
455 if (goog.string.endsWith(this.code, '-handwrit')) {
456 this.type = InputToolType.HWT;
457 } else if (goog.string.endsWith(this.code, '-voice')) {
458 this.type = InputToolType.VOICE;
460 } else if (this.code.indexOf('-k0') >= 0) {
461 this.type = InputToolType.KBD;
462 } else if (goog.string.startsWith(this.code, 'xkb')) {
463 this.type = InputToolType.XKB;
466 // Sets target language code.
467 var codes = this.code.split(/-t|-i0|-k0|:/);
469 if (codes[0] == 'yue-hant') {
470 codes[0] = 'zh-Hant';
472 switch (this.code) {
473 // Currently most of systems doesn't support 'yue-hant', so hack it to
474 // 'zh-hant';
475 case InputToolCode.INPUTMETHOD_CANTONESE_TRADITIONAL:
476 codes[0] = 'zh-Hant';
477 break;
478 case InputToolCode.INPUTMETHOD_PINYIN_CHINESE_SIMPLIFIED:
479 case InputToolCode.INPUTMETHOD_WUBI_CHINESE_SIMPLIFIED:
480 codes[0] = 'zh-Hans';
481 break;
483 if (this.type == InputToolType.XKB) {
484 if (InputTool.XkbId2Language_[this.code]) {
485 this.languageCode = InputTool.XkbId2Language_[this.code];
486 } else {
487 this.languageCode = this.formatLanguageCode_(codes[codes.length - 1]);
489 } else {
490 this.languageCode = this.formatLanguageCode_(codes[0]);
491 // Sets source language target.
492 if (codes[1]) {
493 this.sourceLanguageCode = this.formatLanguageCode_(codes[1]);
497 if (this.type == InputToolType.KBD) {
498 this.parseLayoutCode_();
503 /** @override */
504 InputTool.prototype.toString = function() {
505 return this.code;
510 * Gets the input tool's direction.
512 * @return {string} The direction string - 'rtl' or 'ltr'.
514 InputTool.prototype.getDirection = function() {
515 return this.isRightToLeft() ? 'rtl' : 'ltr';
520 * Gets the input tool's direction.
522 * @return {boolean} Whether is rtl direction of the input tool.
524 InputTool.prototype.isRightToLeft = function() {
525 return goog.array.contains(InputTool.RtlIMEs, this.code) ||
526 goog.array.contains(InputTool.RtlKeyboards, this.code);
531 * Gets whether has status bar.
533 * @return {boolean} Whether has status bar.
535 InputTool.prototype.hasStatusBar = function() {
536 // Don't show status bar in moblie device.
537 if (!GlobalSettings.mobile && this.type == InputToolType.IME) {
538 return /^(zh|yue)/.test(this.code);
540 return false;
545 * Format language to standard language code.
547 * @param {string} code The language code.
548 * @return {string} The standard language code.
549 * @private
551 InputTool.prototype.formatLanguageCode_ = function(code) {
552 // Hack 'und-ethi' to 'et'. The major population use 'ethi' script in
553 // Ethiopia country. So we set 'et' as language code.
554 if (code == 'und-ethi') {
555 return 'et';
558 var parts = code.split('-');
559 var retCode;
560 if (parts.length == 2) {
561 if (parts[1].length == 2) {
562 retCode = parts[0] + '-' + parts[1].toUpperCase();
563 } else {
564 retCode = parts[0] + '-' + parts[1].charAt(0).toUpperCase() +
565 parts[1].slice(1);
567 } else {
568 if (goog.object.containsKey(InputTool.LanguageCodeThreeTwoMap, parts[0])) {
569 retCode = InputTool.LanguageCodeThreeTwoMap[parts[0]];
570 } else {
571 retCode = parts[0];
574 return retCode;
579 * Returns whether the input tool is transliteration or not.
581 * @return {boolean} .
583 InputTool.prototype.isTransliteration = function() {
584 var reg = new RegExp('^(am|ar|bn|el|gu|he|hi|kn|ml|mr|ne|or|fa|pa|ru|sa|' +
585 'sr|si|ta|te|ti|ur|uk|be|bg)');
586 return this.type == InputToolType.IME && reg.test(this.code);
591 * Returns whether the input tool is Latin suggestion or not.
593 * @return {boolean} .
595 InputTool.prototype.isLatin = function() {
596 return this.type == InputToolType.IME &&
597 /^(en|fr|de|it|es|nl|pt|tr|sv|da|fi|no)/.test(this.code);
599 }); // goog.scope