Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: ui/keyboard/resources/common.js

Issue 15176004: Web Component Virtual Keyboard (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview A simple virtual keyboard implementation.
7 */
8
9 var KEY_MODE = 'key';
10 var SHIFT_MODE = 'shift';
11 var NUMBER_MODE = 'number';
12 var SYMBOL_MODE = 'symbol';
13 // TODO(bryeung): tear out all of this mode switching code
14 var MODES = [KEY_MODE, SHIFT_MODE, NUMBER_MODE, SYMBOL_MODE];
15 var currentMode = KEY_MODE;
16 var enterShiftModeOnSpace = false;
17 var MODE_CODES = {};
18 var MODE_TRANSITIONS = {};
19
20 MODE_CODES[KEY_MODE] = 0;
21 MODE_CODES[SHIFT_MODE] = 1;
22 MODE_CODES[NUMBER_MODE] = 2;
23 MODE_CODES[SYMBOL_MODE] = 3;
24
25 MODE_TRANSITIONS[KEY_MODE + SHIFT_MODE] = SHIFT_MODE;
26 MODE_TRANSITIONS[KEY_MODE + NUMBER_MODE] = NUMBER_MODE;
27 MODE_TRANSITIONS[SHIFT_MODE + SHIFT_MODE] = KEY_MODE;
28 MODE_TRANSITIONS[SHIFT_MODE + NUMBER_MODE] = NUMBER_MODE;
29 MODE_TRANSITIONS[NUMBER_MODE + SHIFT_MODE] = SYMBOL_MODE;
30 MODE_TRANSITIONS[NUMBER_MODE + NUMBER_MODE] = KEY_MODE;
31 MODE_TRANSITIONS[SYMBOL_MODE + SHIFT_MODE] = NUMBER_MODE;
32 MODE_TRANSITIONS[SYMBOL_MODE + NUMBER_MODE] = KEY_MODE;
33
34 var KEYBOARDS = {};
35
36 /**
37 * The long-press delay in milliseconds before long-press handler is invoked.
38 * @type {number}
39 */
40 var LONGPRESS_DELAY_MSEC = 500;
41
42 /**
43 * The repeat delay in milliseconds before a key starts repeating. Use the same
44 * rate as Chromebook. (See chrome/browser/chromeos/language_preferences.cc)
45 * @type {number}
46 */
47 var REPEAT_DELAY_MSEC = 500;
48
49 /**
50 * The repeat interval or number of milliseconds between subsequent keypresses.
51 * Use the same rate as Chromebook.
52 * @type {number}
53 */
54 var REPEAT_INTERVAL_MSEC = 50;
55
56 /**
57 * The keyboard layout name currently in use.
58 * @type {string}
59 */
60 var currentKeyboardLayout = 'us';
61
62 /**
63 * A structure to track the currently repeating key on the keyboard.
64 */
65 var repeatKey = {
66 /**
67 * The timer for the delay before repeating behaviour begins.
68 * @type {number|undefined}
69 */
70 timer: undefined,
71
72 /**
73 * The interval timer for issuing keypresses of a repeating key.
74 * @type {number|undefined}
75 */
76 interval: undefined,
77
78 /**
79 * The key which is currently repeating.
80 * @type {BaseKey|undefined}
81 */
82 key: undefined,
83
84 /**
85 * Cancel the repeat timers of the currently active key.
86 */
87 cancel: function() {
88 clearTimeout(this.timer);
89 clearInterval(this.interval);
90 this.timer = undefined;
91 this.interval = undefined;
92 this.key = undefined;
93 }
94 };
95
96 /**
97 * Set the keyboard mode.
98 * @param {string} mode The new mode.
99 */
100 function setMode(mode) {
101 currentMode = mode;
102
103 var rows = KEYBOARDS[currentKeyboardLayout]['rows'];
104 for (var i = 0; i < rows.length; ++i) {
105 rows[i].showMode(currentMode);
106 }
107 }
108
109 /**
110 * Transition the mode according to the given transition.
111 * @param {string} transition The transition to take.
112 */
113 function transitionMode(transition) {
114 setMode(MODE_TRANSITIONS[currentMode + transition]);
115 }
116
117 /**
118 * Send the given key to chrome, via the experimental extension API.
119 * @param {string} keyIdentifier The key to send.
120 */
121 function sendKey(keyIdentifier) {
122 var keyEvent = {
123 keyIdentifier: keyIdentifier
124 };
125 sendKeyEvent(keyEvent);
126
127 // Exit shift mode after pressing any key but space.
128 if (currentMode == SHIFT_MODE && keyIdentifier != 'Spacebar') {
129 transitionMode(SHIFT_MODE);
130 }
131 // Enter shift mode after typing a closing punctuation and then a space for a
132 // new sentence.
133 if (enterShiftModeOnSpace) {
134 enterShiftModeOnSpace = false;
135 if (currentMode != SHIFT_MODE && keyIdentifier == 'Spacebar') {
136 setMode(SHIFT_MODE);
137 }
138 }
139 if (currentMode != SHIFT_MODE &&
140 (keyIdentifier == '.' || keyIdentifier == '?' || keyIdentifier == '!')) {
141 enterShiftModeOnSpace = true;
142 }
143 }
144
145 /**
146 * Add a child div element that represents the content of the given element.
147 * A child div element that represents a text content is added if
148 * opt_textContent is given. Otherwise a child element that represents an image
149 * content is added. If the given element already has a child, the child element
150 * is modified.
151 * @param {Element} element The DOM Element to which the content is added.
152 * @param {string} opt_textContent The text to be inserted.
153 */
154 function addContent(element, opt_textContent) {
155 if (element.childNodes.length > 0) {
156 var content = element.childNodes[0];
157 if (opt_textContent) {
158 content.textContent = opt_textContent;
159 }
160 return;
161 }
162
163 var content = document.createElement('div');
164 if (opt_textContent) {
165 content.textContent = opt_textContent;
166 content.className = 'text-key';
167 } else {
168 content.className = 'image-key';
169 }
170 element.appendChild(content);
171 }
172
173 /**
174 * Set up the event handlers necessary to respond to mouse and touch events on
175 * the virtual keyboard.
176 * @param {BaseKey} key The BaseKey object corresponding to this key.
177 * @param {Element} element The top-level DOM Element to set event handlers on.
178 * @param {Object.<string, function()>} handlers The object that contains key
179 * event handlers in the following form.
180 *
181 * { 'up': keyUpHandler,
182 * 'down': keyDownHandler,
183 * 'long': keyLongHandler }
184 *
185 * keyDownHandler: Called when the key is pressed. This will be called
186 * repeatedly when holding a repeating key.
187 * keyUpHandler: Called when the key is released. This is only called
188 * once per actual key press.
189 * keyLongHandler: Called when the key is long-pressed for
190 * |LONGPRESS_DELAY_MSEC| milliseconds.
191 *
192 * The object does not necessarily contain all the handlers above, but
193 * needs to contain at least one of them.
194 */
195 function setupKeyEventHandlers(key, element, handlers) {
196 var keyDownHandler = handlers['down'];
197 var keyUpHandler = handlers['up'];
198 var keyLongHandler = handlers['long'];
199 if (!(keyDownHandler || keyUpHandler || keyLongPressHandler)) {
200 throw new Error('Invalid handlers passed to setupKeyEventHandlers');
201 }
202
203 /**
204 * Handle a key down event on the virtual key.
205 * @param {UIEvent} evt The UI event which triggered the key down.
206 */
207 var downHandler = function(evt) {
208 // Prevent any of the system gestures from happening.
209 evt.preventDefault();
210
211 // Don't process a key down if the key is already down.
212 if (key.pressed) {
213 return;
214 }
215 key.pressed = true;
216 if (keyDownHandler) {
217 keyDownHandler();
218 }
219 repeatKey.cancel();
220
221 // Start a repeating timer if there is a repeat interval and a function to
222 // process key down events.
223 if (key.repeat && keyDownHandler) {
224 repeatKey.key = key;
225 // The timeout for the repeating timer occurs at
226 // REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC so that the interval
227 // function can handle all repeat keypresses and will get the first one
228 // at the correct time.
229 repeatKey.timer = setTimeout(function() {
230 repeatKey.timer = undefined;
231 repeatKey.interval = setInterval(function() {
232 keyDownHandler();
233 }, REPEAT_INTERVAL_MSEC);
234 }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC));
235 }
236
237 if (keyLongHandler) {
238 // Copy the currentTarget of event, which is neccessary because |evt| can
239 // be modified before |keyLongHandler| is called.
240 var evtCopy = {};
241 evtCopy.currentTarget = evt.currentTarget;
242 key.longPressTimer = setTimeout(function() {
243 keyLongHandler(evtCopy),
244 clearTimeout(key.longPressTimer);
245 delete key.longPressTimer;
246 key.pressed = false;
247 }, LONGPRESS_DELAY_MSEC);
248 }
249 };
250
251 /**
252 * Handle a key up event on the virtual key.
253 * @param {UIEvent} evt The UI event which triggered the key up.
254 */
255 var upHandler = function(evt) {
256 // Prevent any of the system gestures from happening.
257 evt.preventDefault();
258
259 // Reset long-press timer.
260 if (key.longPressTimer) {
261 clearTimeout(key.longPressTimer);
262 delete key.longPressTimer;
263 }
264
265 // If they key was not actually pressed do not send a key up event.
266 if (!key.pressed) {
267 return;
268 }
269 key.pressed = false;
270
271 // Cancel running repeat timer for the released key only.
272 if (repeatKey.key == key) {
273 repeatKey.cancel();
274 }
275
276 if (keyUpHandler) {
277 keyUpHandler();
278 }
279 };
280
281 // Setup mouse event handlers.
282 element.addEventListener('mousedown', downHandler);
283 element.addEventListener('mouseup', upHandler);
284
285 // Setup touch handlers.
286 element.addEventListener('touchstart', downHandler);
287 element.addEventListener('touchend', upHandler);
288 }
289
290 /**
291 * Create closure for the sendKey function.
292 * @param {string} key The key paramater to sendKey.
293 * @return {function()} A function which calls sendKey(key).
294 */
295 function sendKeyFunction(key) {
296 return function() {
297 sendKey(key);
298 };
299 }
300
301 /**
302 * Plain-old-data class to represent a character.
303 * @param {string} display The HTML to be displayed.
304 * @param {string} id The key identifier for this Character.
305 * @constructor
306 */
307 function Character(display, id) {
308 this.display = display;
309 this.keyIdentifier = id;
310 }
311
312 /**
313 * Convenience function to make the keyboard data more readable.
314 * @param {string} display The display for the created Character.
315 * @param {string} opt_id The id for the created Character.
316 * @return {Character} A character that contains display and opt_id. If
317 * opt_id is omitted, display is used as the id.
318 */
319 function C(display, opt_id) {
320 var id = opt_id || display;
321 return new Character(display, id);
322 }
323
324 /**
325 * An abstract base-class for all keys on the keyboard.
326 * @constructor
327 */
328 function BaseKey() {}
329
330 BaseKey.prototype = {
331 /**
332 * The cell type of this key. Determines the background colour.
333 * @type {string}
334 */
335 cellType_: '',
336
337 /**
338 * If true, holding this key will issue repeat keypresses.
339 * @type {boolean}
340 */
341 repeat_: false,
342
343 /**
344 * Track the pressed state of the key. This is true if currently pressed.
345 * @type {boolean}
346 */
347 pressed_: false,
348
349 /**
350 * Get the repeat behaviour of the key.
351 * @return {boolean} True if the key will repeat.
352 */
353 get repeat() {
354 return this.repeat_;
355 },
356
357 /**
358 * Set the repeat behaviour of the key
359 * @param {boolean} repeat True if the key should repeat.
360 */
361 set repeat(repeat) {
362 this.repeat_ = repeat;
363 },
364
365 /**
366 * Get the pressed state of the key.
367 * @return {boolean} True if the key is currently pressed.
368 */
369 get pressed() {
370 return this.pressed_;
371 },
372
373 /**
374 * Set the pressed state of the key.
375 * @param {boolean} pressed True if the key is currently pressed.
376 */
377 set pressed(pressed) {
378 this.pressed_ = pressed;
379 },
380
381 /**
382 * Create the DOM elements for the given keyboard mode. Must be overridden.
383 * @param {string} mode The keyboard mode to create elements for.
384 * @return {Element} The top-level DOM Element for the key.
385 */
386 makeDOM: function(mode) {
387 throw new Error('makeDOM not implemented in BaseKey');
388 },
389 };
390
391 /**
392 * A simple key which displays Characters.
393 * @param {Object} key The Character for KEY_MODE.
394 * @param {Object} shift The Character for SHIFT_MODE.
395 * @param {Object} num The Character for NUMBER_MODE.
396 * @param {Object} symbol The Character for SYMBOL_MODE.
397 * @param {string} className An optional class name for the key.
398 * @constructor
399 * @extends {BaseKey}
400 */
401 function Key(key, shift, num, symbol, className) {
402 this.modeElements_ = {};
403 this.cellType_ = '';
404 this.className_ = (className) ? 'key ' + className : 'key';
405
406 this.modes_ = {};
407 this.modes_[KEY_MODE] = key;
408 this.modes_[SHIFT_MODE] = shift;
409 this.modes_[NUMBER_MODE] = num;
410 this.modes_[SYMBOL_MODE] = symbol;
411 }
412
413 Key.prototype = {
414 __proto__: BaseKey.prototype,
415
416 /** @override */
417 makeDOM: function(mode) {
418 if (!this.modes_[mode]) {
419 return null;
420 }
421
422 this.modeElements_[mode] = document.createElement('div');
423 var element = this.modeElements_[mode];
424 element.className = this.className_;
425
426 addContent(element, this.modes_[mode].display);
427
428 setupKeyEventHandlers(this, element,
429 { 'up': sendKeyFunction(this.modes_[mode].keyIdentifier) });
430 return element;
431 }
432 };
433
434 /**
435 * A key which displays an SVG image.
436 * @param {string} className The class that provides the image.
437 * @param {string} keyId The key identifier for the key.
438 * @param {boolean} opt_repeat True if the key should repeat.
439 * @constructor
440 * @extends {BaseKey}
441 */
442 function SvgKey(className, keyId, opt_repeat) {
443 this.modeElements_ = {};
444 this.cellType_ = 'nc';
445 this.className_ = className;
446 this.keyId_ = keyId;
447 this.repeat_ = opt_repeat || false;
448 }
449
450 SvgKey.prototype = {
451 __proto__: BaseKey.prototype,
452
453 /** @override */
454 makeDOM: function(mode) {
455 this.modeElements_[mode] = document.createElement('div');
456 this.modeElements_[mode].className = 'key dark';
457 this.modeElements_[mode].classList.add(this.className_);
458 addContent(this.modeElements_[mode]);
459
460 // send the key event on key down if key repeat is enabled
461 var handler = this.repeat_ ? { 'down' : sendKeyFunction(this.keyId_) } :
462 { 'up' : sendKeyFunction(this.keyId_) };
463 setupKeyEventHandlers(this, this.modeElements_[mode], handler);
464
465 return this.modeElements_[mode];
466 }
467 };
468
469 /**
470 * A Key that remains the same through all modes.
471 * @param {string} className The class name for the key.
472 * @param {string} content The display text for the key.
473 * @param {string} keyId The key identifier for the key.
474 * @constructor
475 * @extends {BaseKey}
476 */
477 function SpecialKey(className, content, keyId) {
478 this.modeElements_ = {};
479 this.cellType_ = 'nc';
480 this.content_ = content;
481 this.keyId_ = keyId;
482 this.className_ = className;
483 }
484
485 SpecialKey.prototype = {
486 __proto__: BaseKey.prototype,
487
488 /** @override */
489 makeDOM: function(mode) {
490 this.modeElements_[mode] = document.createElement('div');
491 this.modeElements_[mode].className = 'key dark';
492 this.modeElements_[mode].classList.add(this.className_);
493 addContent(this.modeElements_[mode], this.content_);
494
495 setupKeyEventHandlers(this, this.modeElements_[mode],
496 { 'up': sendKeyFunction(this.keyId_) });
497
498 return this.modeElements_[mode];
499 }
500 };
501
502 /**
503 * A shift key.
504 * @constructor
505 * @param {string} className The class name for the key.
506 * @extends {BaseKey}
507 */
508 function ShiftKey(className) {
509 this.modeElements_ = {};
510 this.cellType_ = 'nc';
511 this.className_ = className;
512 }
513
514 ShiftKey.prototype = {
515 __proto__: BaseKey.prototype,
516
517 /** @override */
518 makeDOM: function(mode) {
519 this.modeElements_[mode] = document.createElement('div');
520 this.modeElements_[mode].className = 'key shift dark';
521 this.modeElements_[mode].classList.add(this.className_);
522
523 if (mode == KEY_MODE || mode == SHIFT_MODE) {
524 addContent(this.modeElements_[mode]);
525 } else if (mode == NUMBER_MODE) {
526 addContent(this.modeElements_[mode], 'more');
527 } else if (mode == SYMBOL_MODE) {
528 addContent(this.modeElements_[mode], '#123');
529 }
530
531 if (mode == SHIFT_MODE || mode == SYMBOL_MODE) {
532 this.modeElements_[mode].classList.add('moddown');
533 } else {
534 this.modeElements_[mode].classList.remove('moddown');
535 }
536
537 setupKeyEventHandlers(this, this.modeElements_[mode],
538 { 'down': function() {
539 transitionMode(SHIFT_MODE);
540 }});
541
542 return this.modeElements_[mode];
543 },
544 };
545
546 /**
547 * The symbol key: switches the keyboard into symbol mode.
548 * @constructor
549 * @extends {BaseKey}
550 */
551 function SymbolKey() {
552 this.modeElements_ = {};
553 this.cellType_ = 'nc';
554 }
555
556 SymbolKey.prototype = {
557 __proto__: BaseKey.prototype,
558
559 /** @override */
560 makeDOM: function(mode, height) {
561 this.modeElements_[mode] = document.createElement('div');
562 this.modeElements_[mode].className = 'key symbol dark';
563
564 if (mode == KEY_MODE || mode == SHIFT_MODE) {
565 addContent(this.modeElements_[mode], '#123');
566 } else if (mode == NUMBER_MODE || mode == SYMBOL_MODE) {
567 addContent(this.modeElements_[mode], 'abc');
568 }
569
570 if (mode == NUMBER_MODE || mode == SYMBOL_MODE) {
571 this.modeElements_[mode].classList.add('moddown');
572 } else {
573 this.modeElements_[mode].classList.remove('moddown');
574 }
575
576 setupKeyEventHandlers(this, this.modeElements_[mode],
577 { 'down': function() {
578 transitionMode(NUMBER_MODE);
579 }});
580
581 return this.modeElements_[mode];
582 }
583 };
584
585 /**
586 * The ".com" key.
587 * @constructor
588 * @extends {BaseKey}
589 */
590 function DotComKey() {
591 this.modeElements_ = {};
592 this.cellType_ = 'nc';
593 }
594
595 DotComKey.prototype = {
596 __proto__: BaseKey.prototype,
597
598 /** @override */
599 makeDOM: function(mode) {
600 this.modeElements_[mode] = document.createElement('div');
601 this.modeElements_[mode].className = 'key com dark';
602 addContent(this.modeElements_[mode], '.com');
603
604 setupKeyEventHandlers(this, this.modeElements_[mode],
605 { 'up': function() {
606 sendKey('.');
607 sendKey('c');
608 sendKey('o');
609 sendKey('m');
610 }});
611
612 return this.modeElements_[mode];
613 }
614 };
615
616 /**
617 * The key that hides the keyboard.
618 * @constructor
619 * @extends {BaseKey}
620 */
621 function HideKeyboardKey() {
622 this.modeElements_ = {};
623 this.cellType_ = 'nc';
624 }
625
626 HideKeyboardKey.prototype = {
627 __proto__: BaseKey.prototype,
628
629 /** @override */
630 makeDOM: function(mode) {
631 this.modeElements_[mode] = document.createElement('div');
632 this.modeElements_[mode].className = 'key hide dark';
633 addContent(this.modeElements_[mode]);
634
635 setupKeyEventHandlers(this, this.modeElements_[mode],
636 { 'down': function() { console.log('Hide the keyboard!'); } });
637
638 return this.modeElements_[mode];
639 }
640 };
641
642 /**
643 * The mic key: activate speech input.
644 * @constructor
645 * @extends {BaseKey}
646 */
647 function MicKey() {
648 this.modeElements_ = {};
649 this.recognition_ = new webkitSpeechRecognition();
650 this.recognition_.onstart = this.onStartHandler.bind(this);
651 this.recognition_.onresult = this.onResultHandler.bind(this);
652 this.recognition_.onerror = this.onErrorHandler.bind(this);
653 this.recognition_.onend = this.onEndHandler.bind(this);
654 this.finalResult_ = '';
655 this.recognizing_ = false;
656 this.cellType_ = 'nc';
657 }
658
659 MicKey.prototype = {
660 __proto__: BaseKey.prototype,
661
662 /**
663 * Event handler for mouse/touch down events.
664 */
665 onDown: function() {
666 if (this.recognizing_) {
667 this.recognition_.stop();
668 return;
669 }
670 this.recognition_.start();
671 },
672
673 /**
674 * Speech recognition started. Change mic key's icon.
675 */
676 onStartHandler: function() {
677 this.recognizing_ = true;
678 this.finalResult_ = '';
679 for (var i = 0; i < MODES.length; ++i)
680 this.modeElements_[MODES[i]].classList.add('start');
681 },
682
683 /**
684 * Speech recognizer returns a result.
685 * @param{Event} e The SpeechRecognition event that is raised each time there
686 * are any changes to interim or final results.
687 */
688 onResultHandler: function(e) {
689 for (var i = e.resultIndex; i < e.results.length; i++) {
690 if (e.results[i].isFinal)
691 this.finalResult_ = e.results[i][0].transcript;
692 }
693 for (var i = 0; i < this.finalResult_.length; i++) {
694 var keyEvent = {
695 keyIdentifier: this.finalResult_.charAt(i)
696 };
697 sendKeyEvent(keyEvent);
698 }
699 },
700
701 /**
702 * Speech recognizer returns an error.
703 * @param{Event} e The SpeechRecognitionError event that is raised each time
704 * there is an error.
705 */
706 onErrorHandler: function(e) {
707 console.error('error code = ' + e.error);
708 },
709
710 /**
711 * Speech recognition ended. Reset mic key's icon.
712 */
713 onEndHandler: function() {
714 for (var i = 0; i < MODES.length; ++i)
715 this.modeElements_[MODES[i]].classList.remove('start');
716
717 this.recognizing_ = false;
718 },
719
720 /** @override */
721 makeDOM: function(mode) {
722 this.modeElements_[mode] = document.createElement('div');
723 this.modeElements_[mode].className = 'key mic';
724 addContent(this.modeElements_[mode]);
725
726 setupKeyEventHandlers(this, this.modeElements_[mode],
727 { 'down': this.onDown.bind(this) });
728
729 return this.modeElements_[mode];
730 }
731 };
732
733 /**
734 * A container for keys.
735 * @param {number} position The position of the row (0-3).
736 * @param {Array.<BaseKey>} keys The keys in the row.
737 * @constructor
738 */
739 function Row(position, keys) {
740 this.position_ = position;
741 this.keys_ = keys;
742 this.element_ = null;
743 this.modeElements_ = {};
744 }
745
746 Row.prototype = {
747 /**
748 * Create the DOM elements for the row.
749 * @return {Element} The top-level DOM Element for the row.
750 */
751 makeDOM: function() {
752 this.element_ = document.createElement('div');
753 this.element_.className = 'row';
754 for (var i = 0; i < MODES.length; ++i) {
755 var mode = MODES[i];
756 this.modeElements_[mode] = document.createElement('div');
757 this.modeElements_[mode].style.display = 'none';
758 this.element_.appendChild(this.modeElements_[mode]);
759 }
760
761 for (var j = 0; j < this.keys_.length; ++j) {
762 var key = this.keys_[j];
763 for (var i = 0; i < MODES.length; ++i) {
764 var keyDom = key.makeDOM(MODES[i]);
765 if (keyDom) {
766 this.modeElements_[MODES[i]].appendChild(keyDom);
767 }
768 }
769 }
770
771 for (var i = 0; i < MODES.length; ++i) {
772 var clearingDiv = document.createElement('div');
773 clearingDiv.style.clear = 'both';
774 this.modeElements_[MODES[i]].appendChild(clearingDiv);
775 }
776
777 return this.element_;
778 },
779
780 /**
781 * Shows the given mode.
782 * @param {string} mode The mode to show.
783 */
784 showMode: function(mode) {
785 for (var i = 0; i < MODES.length; ++i) {
786 this.modeElements_[MODES[i]].style.display = 'none';
787 }
788 this.modeElements_[mode].style.display = '-webkit-box';
789 },
790
791 /**
792 * Returns the size of keys this row contains.
793 * @return {number} The size of keys.
794 */
795 get length() {
796 return this.keys_.length;
797 }
798 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698