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

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

Powered by Google App Engine
This is Rietveld 408576698