| Index: ui/keyboard/resources/common.js
|
| diff --git a/ui/keyboard/resources/common.js b/ui/keyboard/resources/common.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..03aa5509362eff8ab1e37db8234e5084672ae39b
|
| --- /dev/null
|
| +++ b/ui/keyboard/resources/common.js
|
| @@ -0,0 +1,716 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/**
|
| + * @fileoverview A simple virtual keyboard implementation.
|
| + */
|
| +
|
| +var KEY_MODE = 'key';
|
| +var SHIFT_MODE = 'shift';
|
| +var NUMBER_MODE = 'number';
|
| +var SYMBOL_MODE = 'symbol';
|
| +// TODO(bryeung): tear out all of this mode switching code
|
| +var MODES = [KEY_MODE, SHIFT_MODE, NUMBER_MODE, SYMBOL_MODE];
|
| +var currentMode = KEY_MODE;
|
| +var enterShiftModeOnSpace = false;
|
| +var MODE_CODES = {};
|
| +var MODE_TRANSITIONS = {};
|
| +
|
| +MODE_CODES[KEY_MODE] = 0;
|
| +MODE_CODES[SHIFT_MODE] = 1;
|
| +MODE_CODES[NUMBER_MODE] = 2;
|
| +MODE_CODES[SYMBOL_MODE] = 3;
|
| +
|
| +MODE_TRANSITIONS[KEY_MODE + SHIFT_MODE] = SHIFT_MODE;
|
| +MODE_TRANSITIONS[KEY_MODE + NUMBER_MODE] = NUMBER_MODE;
|
| +MODE_TRANSITIONS[SHIFT_MODE + SHIFT_MODE] = KEY_MODE;
|
| +MODE_TRANSITIONS[SHIFT_MODE + NUMBER_MODE] = NUMBER_MODE;
|
| +MODE_TRANSITIONS[NUMBER_MODE + SHIFT_MODE] = SYMBOL_MODE;
|
| +MODE_TRANSITIONS[NUMBER_MODE + NUMBER_MODE] = KEY_MODE;
|
| +MODE_TRANSITIONS[SYMBOL_MODE + SHIFT_MODE] = NUMBER_MODE;
|
| +MODE_TRANSITIONS[SYMBOL_MODE + NUMBER_MODE] = KEY_MODE;
|
| +
|
| +var KEYBOARDS = {};
|
| +
|
| +/**
|
| + * The long-press delay in milliseconds before long-press handler is invoked.
|
| + * @type {number}
|
| + */
|
| +var LONGPRESS_DELAY_MSEC = 500;
|
| +
|
| +/**
|
| + * The repeat delay in milliseconds before a key starts repeating. Use the same
|
| + * rate as Chromebook. (See chrome/browser/chromeos/language_preferences.cc)
|
| + * @type {number}
|
| + */
|
| +var REPEAT_DELAY_MSEC = 500;
|
| +
|
| +/**
|
| + * The repeat interval or number of milliseconds between subsequent keypresses.
|
| + * Use the same rate as Chromebook.
|
| + * @type {number}
|
| + */
|
| +var REPEAT_INTERVAL_MSEC = 50;
|
| +
|
| +/**
|
| + * The keyboard layout name currently in use.
|
| + * @type {string}
|
| + */
|
| +var currentKeyboardLayout = 'us';
|
| +
|
| +/**
|
| + * A structure to track the currently repeating key on the keyboard.
|
| + */
|
| +var repeatKey = {
|
| + /**
|
| + * The timer for the delay before repeating behaviour begins.
|
| + * @type {number|undefined}
|
| + */
|
| + timer: undefined,
|
| +
|
| + /**
|
| + * The interval timer for issuing keypresses of a repeating key.
|
| + * @type {number|undefined}
|
| + */
|
| + interval: undefined,
|
| +
|
| + /**
|
| + * The key which is currently repeating.
|
| + * @type {BaseKey|undefined}
|
| + */
|
| + key: undefined,
|
| +
|
| + /**
|
| + * Cancel the repeat timers of the currently active key.
|
| + */
|
| + cancel: function() {
|
| + clearTimeout(this.timer);
|
| + clearInterval(this.interval);
|
| + this.timer = undefined;
|
| + this.interval = undefined;
|
| + this.key = undefined;
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * Set the keyboard mode.
|
| + * @param {string} mode The new mode.
|
| + */
|
| +function setMode(mode) {
|
| + currentMode = mode;
|
| +
|
| + var rows = KEYBOARDS[currentKeyboardLayout]['rows'];
|
| + for (var i = 0; i < rows.length; ++i) {
|
| + rows[i].showMode(currentMode);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Transition the mode according to the given transition.
|
| + * @param {string} transition The transition to take.
|
| + */
|
| +function transitionMode(transition) {
|
| + setMode(MODE_TRANSITIONS[currentMode + transition]);
|
| +}
|
| +
|
| +function logIfError() {
|
| + if (chrome.runtime.lastError) {
|
| + console.log(chrome.runtime.lastError);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Send the given key to chrome, via the experimental extension API.
|
| + * @param {string} keyIdentifier The key to send.
|
| + */
|
| +function sendKey(keyIdentifier) {
|
| + // FIXME(bryeung)
|
| + console.log('Typed: ' + keyIdentifier);
|
| + var keyEvent = {
|
| + type: 'keydown',
|
| + keyIdentifier: keyIdentifier
|
| + };
|
| + chrome.experimental.input.virtualKeyboard.sendKeyboardEvent(keyEvent,
|
| + logIfError);
|
| + keyEvent.type = 'keyup';
|
| + chrome.experimental.input.virtualKeyboard.sendKeyboardEvent(keyEvent,
|
| + logIfError);
|
| +
|
| + // Exit shift mode after pressing any key but space.
|
| + if (currentMode == SHIFT_MODE && keyIdentifier != 'Spacebar') {
|
| + transitionMode(SHIFT_MODE);
|
| + }
|
| + // Enter shift mode after typing a closing punctuation and then a space for a
|
| + // new sentence.
|
| + if (enterShiftModeOnSpace) {
|
| + enterShiftModeOnSpace = false;
|
| + if (currentMode != SHIFT_MODE && keyIdentifier == 'Spacebar') {
|
| + setMode(SHIFT_MODE);
|
| + }
|
| + }
|
| + if (currentMode != SHIFT_MODE &&
|
| + (keyIdentifier == '.' || keyIdentifier == '?' || keyIdentifier == '!')) {
|
| + enterShiftModeOnSpace = true;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Add a child div element that represents the content of the given element.
|
| + * A child div element that represents a text content is added if
|
| + * opt_textContent is given. Otherwise a child element that represents an image
|
| + * content is added. If the given element already has a child, the child element
|
| + * is modified.
|
| + * @param {Element} element The DOM Element to which the content is added.
|
| + * @param {string} opt_textContent The text to be inserted.
|
| + */
|
| +function addContent(element, opt_textContent) {
|
| + if (element.childNodes.length > 0) {
|
| + var content = element.childNodes[0];
|
| + if (opt_textContent) {
|
| + content.textContent = opt_textContent;
|
| + }
|
| + return;
|
| + }
|
| +
|
| + var content = document.createElement('div');
|
| + if (opt_textContent) {
|
| + content.textContent = opt_textContent;
|
| + content.className = 'text-key';
|
| + } else {
|
| + content.className = 'image-key';
|
| + }
|
| + element.appendChild(content);
|
| +}
|
| +
|
| +/**
|
| + * Set up the event handlers necessary to respond to mouse and touch events on
|
| + * the virtual keyboard.
|
| + * @param {BaseKey} key The BaseKey object corresponding to this key.
|
| + * @param {Element} element The top-level DOM Element to set event handlers on.
|
| + * @param {Object.<string, function()>} handlers The object that contains key
|
| + * event handlers in the following form.
|
| + *
|
| + * { 'up': keyUpHandler,
|
| + * 'down': keyDownHandler,
|
| + * 'long': keyLongHandler }
|
| + *
|
| + * keyDownHandler: Called when the key is pressed. This will be called
|
| + * repeatedly when holding a repeating key.
|
| + * keyUpHandler: Called when the key is released. This is only called
|
| + * once per actual key press.
|
| + * keyLongHandler: Called when the key is long-pressed for
|
| + * |LONGPRESS_DELAY_MSEC| milliseconds.
|
| + *
|
| + * The object does not necessarily contain all the handlers above, but
|
| + * needs to contain at least one of them.
|
| + */
|
| +function setupKeyEventHandlers(key, element, handlers) {
|
| + var keyDownHandler = handlers['down'];
|
| + var keyUpHandler = handlers['up'];
|
| + var keyLongHandler = handlers['long'];
|
| + if (!(keyDownHandler || keyUpHandler || keyLongPressHandler)) {
|
| + throw new Error('Invalid handlers passed to setupKeyEventHandlers');
|
| + }
|
| +
|
| + /**
|
| + * Handle a key down event on the virtual key.
|
| + * @param {UIEvent} evt The UI event which triggered the key down.
|
| + */
|
| + var downHandler = function(evt) {
|
| + // Prevent any of the system gestures from happening.
|
| + evt.preventDefault();
|
| +
|
| + // Don't process a key down if the key is already down.
|
| + if (key.pressed) {
|
| + return;
|
| + }
|
| + key.pressed = true;
|
| + if (keyDownHandler) {
|
| + keyDownHandler();
|
| + }
|
| + repeatKey.cancel();
|
| +
|
| + // Start a repeating timer if there is a repeat interval and a function to
|
| + // process key down events.
|
| + if (key.repeat && keyDownHandler) {
|
| + repeatKey.key = key;
|
| + // The timeout for the repeating timer occurs at
|
| + // REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC so that the interval
|
| + // function can handle all repeat keypresses and will get the first one
|
| + // at the correct time.
|
| + repeatKey.timer = setTimeout(function() {
|
| + repeatKey.timer = undefined;
|
| + repeatKey.interval = setInterval(function() {
|
| + keyDownHandler();
|
| + }, REPEAT_INTERVAL_MSEC);
|
| + }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC));
|
| + }
|
| +
|
| + if (keyLongHandler) {
|
| + // Copy the currentTarget of event, which is neccessary because |evt| can
|
| + // be modified before |keyLongHandler| is called.
|
| + var evtCopy = {};
|
| + evtCopy.currentTarget = evt.currentTarget;
|
| + key.longPressTimer = setTimeout(function() {
|
| + keyLongHandler(evtCopy),
|
| + clearTimeout(key.longPressTimer);
|
| + delete key.longPressTimer;
|
| + key.pressed = false;
|
| + }, LONGPRESS_DELAY_MSEC);
|
| + }
|
| + };
|
| +
|
| + /**
|
| + * Handle a key up event on the virtual key.
|
| + * @param {UIEvent} evt The UI event which triggered the key up.
|
| + */
|
| + var upHandler = function(evt) {
|
| + // Prevent any of the system gestures from happening.
|
| + evt.preventDefault();
|
| +
|
| + // Reset long-press timer.
|
| + if (key.longPressTimer) {
|
| + clearTimeout(key.longPressTimer);
|
| + delete key.longPressTimer;
|
| + }
|
| +
|
| + // If they key was not actually pressed do not send a key up event.
|
| + if (!key.pressed) {
|
| + return;
|
| + }
|
| + key.pressed = false;
|
| +
|
| + // Cancel running repeat timer for the released key only.
|
| + if (repeatKey.key == key) {
|
| + repeatKey.cancel();
|
| + }
|
| +
|
| + if (keyUpHandler) {
|
| + keyUpHandler();
|
| + }
|
| + };
|
| +
|
| + // Setup mouse event handlers.
|
| + element.addEventListener('mousedown', downHandler);
|
| + element.addEventListener('mouseup', upHandler);
|
| +
|
| + // Setup touch handlers.
|
| + element.addEventListener('touchstart', downHandler);
|
| + element.addEventListener('touchend', upHandler);
|
| +}
|
| +
|
| +/**
|
| + * Create closure for the sendKey function.
|
| + * @param {string} key The key paramater to sendKey.
|
| + * @return {function()} A function which calls sendKey(key).
|
| + */
|
| +function sendKeyFunction(key) {
|
| + return function() {
|
| + sendKey(key);
|
| + };
|
| +}
|
| +
|
| +/**
|
| + * Plain-old-data class to represent a character.
|
| + * @param {string} display The HTML to be displayed.
|
| + * @param {string} id The key identifier for this Character.
|
| + * @constructor
|
| + */
|
| +function Character(display, id) {
|
| + this.display = display;
|
| + this.keyIdentifier = id;
|
| +}
|
| +
|
| +/**
|
| + * Convenience function to make the keyboard data more readable.
|
| + * @param {string} display The display for the created Character.
|
| + * @param {string} opt_id The id for the created Character.
|
| + * @return {Character} A character that contains display and opt_id. If
|
| + * opt_id is omitted, display is used as the id.
|
| + */
|
| +function C(display, opt_id) {
|
| + var id = opt_id || display;
|
| + return new Character(display, id);
|
| +}
|
| +
|
| +/**
|
| + * An abstract base-class for all keys on the keyboard.
|
| + * @constructor
|
| + */
|
| +function BaseKey() {}
|
| +
|
| +BaseKey.prototype = {
|
| + /**
|
| + * The cell type of this key. Determines the background colour.
|
| + * @type {string}
|
| + */
|
| + cellType_: '',
|
| +
|
| + /**
|
| + * If true, holding this key will issue repeat keypresses.
|
| + * @type {boolean}
|
| + */
|
| + repeat_: false,
|
| +
|
| + /**
|
| + * Track the pressed state of the key. This is true if currently pressed.
|
| + * @type {boolean}
|
| + */
|
| + pressed_: false,
|
| +
|
| + /**
|
| + * Get the repeat behaviour of the key.
|
| + * @return {boolean} True if the key will repeat.
|
| + */
|
| + get repeat() {
|
| + return this.repeat_;
|
| + },
|
| +
|
| + /**
|
| + * Set the repeat behaviour of the key
|
| + * @param {boolean} repeat True if the key should repeat.
|
| + */
|
| + set repeat(repeat) {
|
| + this.repeat_ = repeat;
|
| + },
|
| +
|
| + /**
|
| + * Get the pressed state of the key.
|
| + * @return {boolean} True if the key is currently pressed.
|
| + */
|
| + get pressed() {
|
| + return this.pressed_;
|
| + },
|
| +
|
| + /**
|
| + * Set the pressed state of the key.
|
| + * @param {boolean} pressed True if the key is currently pressed.
|
| + */
|
| + set pressed(pressed) {
|
| + this.pressed_ = pressed;
|
| + },
|
| +
|
| + /**
|
| + * Create the DOM elements for the given keyboard mode. Must be overridden.
|
| + * @param {string} mode The keyboard mode to create elements for.
|
| + * @return {Element} The top-level DOM Element for the key.
|
| + */
|
| + makeDOM: function(mode) {
|
| + throw new Error('makeDOM not implemented in BaseKey');
|
| + },
|
| +};
|
| +
|
| +/**
|
| + * A simple key which displays Characters.
|
| + * @param {Object} key The Character for KEY_MODE.
|
| + * @param {Object} shift The Character for SHIFT_MODE.
|
| + * @param {string} className An optional class name for the key.
|
| + * @constructor
|
| + * @extends {BaseKey}
|
| + */
|
| +function Key(key, shift, className) {
|
| + this.modeElements_ = {};
|
| + this.cellType_ = '';
|
| + this.className_ = (className) ? 'key ' + className : 'key';
|
| +
|
| + this.modes_ = {};
|
| + this.modes_[KEY_MODE] = key;
|
| + this.modes_[SHIFT_MODE] = shift;
|
| +}
|
| +
|
| +Key.prototype = {
|
| + __proto__: BaseKey.prototype,
|
| +
|
| + /** @override */
|
| + makeDOM: function(mode) {
|
| + if (!this.modes_[mode]) {
|
| + return null;
|
| + }
|
| +
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + var element = this.modeElements_[mode];
|
| + element.className = this.className_;
|
| +
|
| + addContent(element, this.modes_[mode].display);
|
| +
|
| + setupKeyEventHandlers(this, element,
|
| + { 'up': sendKeyFunction(this.modes_[mode].keyIdentifier) });
|
| + return element;
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * A key which displays an SVG image.
|
| + * @param {string} className The class that provides the image.
|
| + * @param {string} keyId The key identifier for the key.
|
| + * @param {boolean} opt_repeat True if the key should repeat.
|
| + * @constructor
|
| + * @extends {BaseKey}
|
| + */
|
| +function SvgKey(className, keyId, opt_repeat) {
|
| + this.modeElements_ = {};
|
| + this.cellType_ = 'nc';
|
| + this.className_ = className;
|
| + this.keyId_ = keyId;
|
| + this.repeat_ = opt_repeat || false;
|
| +}
|
| +
|
| +SvgKey.prototype = {
|
| + __proto__: BaseKey.prototype,
|
| +
|
| + /** @override */
|
| + makeDOM: function(mode) {
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + this.modeElements_[mode].className = 'key';
|
| + this.modeElements_[mode].classList.add(this.className_);
|
| + addContent(this.modeElements_[mode]);
|
| +
|
| + // send the key event on key down if key repeat is enabled
|
| + var handler = this.repeat_ ? { 'down' : sendKeyFunction(this.keyId_) } :
|
| + { 'up' : sendKeyFunction(this.keyId_) };
|
| + setupKeyEventHandlers(this, this.modeElements_[mode], handler);
|
| +
|
| + return this.modeElements_[mode];
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * A Key that remains the same through all modes.
|
| + * @param {string} className The class name for the key.
|
| + * @param {string} content The display text for the key.
|
| + * @param {string} keyId The key identifier for the key.
|
| + * @constructor
|
| + * @extends {BaseKey}
|
| + */
|
| +function SpecialKey(className, content, keyId) {
|
| + this.modeElements_ = {};
|
| + this.cellType_ = 'nc';
|
| + this.content_ = content;
|
| + this.keyId_ = keyId;
|
| + this.className_ = className;
|
| +}
|
| +
|
| +SpecialKey.prototype = {
|
| + __proto__: BaseKey.prototype,
|
| +
|
| + /** @override */
|
| + makeDOM: function(mode) {
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + this.modeElements_[mode].className = 'key';
|
| + this.modeElements_[mode].classList.add(this.className_);
|
| + addContent(this.modeElements_[mode], this.content_);
|
| +
|
| + setupKeyEventHandlers(this, this.modeElements_[mode],
|
| + { 'up': sendKeyFunction(this.keyId_) });
|
| +
|
| + return this.modeElements_[mode];
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * A shift key.
|
| + * @constructor
|
| + * @param {string} className The class name for the key.
|
| + * @extends {BaseKey}
|
| + */
|
| +function ShiftKey(className) {
|
| + this.modeElements_ = {};
|
| + this.cellType_ = 'nc';
|
| + this.className_ = className;
|
| +}
|
| +
|
| +ShiftKey.prototype = {
|
| + __proto__: BaseKey.prototype,
|
| +
|
| + /** @override */
|
| + makeDOM: function(mode) {
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + this.modeElements_[mode].className = 'key shift';
|
| + this.modeElements_[mode].classList.add(this.className_);
|
| +
|
| + if (mode == KEY_MODE || mode == SHIFT_MODE) {
|
| + addContent(this.modeElements_[mode]);
|
| + } else if (mode == NUMBER_MODE) {
|
| + addContent(this.modeElements_[mode], 'more');
|
| + } else if (mode == SYMBOL_MODE) {
|
| + addContent(this.modeElements_[mode], '#123');
|
| + }
|
| +
|
| + if (mode == SHIFT_MODE || mode == SYMBOL_MODE) {
|
| + this.modeElements_[mode].classList.add('moddown');
|
| + } else {
|
| + this.modeElements_[mode].classList.remove('moddown');
|
| + }
|
| +
|
| + setupKeyEventHandlers(this, this.modeElements_[mode],
|
| + { 'down': function() {
|
| + transitionMode(SHIFT_MODE);
|
| + }});
|
| +
|
| + return this.modeElements_[mode];
|
| + },
|
| +};
|
| +
|
| +/**
|
| + * The symbol key: switches the keyboard into symbol mode.
|
| + * @constructor
|
| + * @extends {BaseKey}
|
| + */
|
| +function SymbolKey() {
|
| + this.modeElements_ = {};
|
| + this.cellType_ = 'nc';
|
| +}
|
| +
|
| +SymbolKey.prototype = {
|
| + __proto__: BaseKey.prototype,
|
| +
|
| + /** @override */
|
| + makeDOM: function(mode, height) {
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + this.modeElements_[mode].className = 'key symbol';
|
| +
|
| + if (mode == KEY_MODE || mode == SHIFT_MODE) {
|
| + addContent(this.modeElements_[mode], '#123');
|
| + } else if (mode == NUMBER_MODE || mode == SYMBOL_MODE) {
|
| + addContent(this.modeElements_[mode], 'abc');
|
| + }
|
| +
|
| + if (mode == NUMBER_MODE || mode == SYMBOL_MODE) {
|
| + this.modeElements_[mode].classList.add('moddown');
|
| + } else {
|
| + this.modeElements_[mode].classList.remove('moddown');
|
| + }
|
| +
|
| + setupKeyEventHandlers(this, this.modeElements_[mode],
|
| + { 'down': function() {
|
| + transitionMode(NUMBER_MODE);
|
| + }});
|
| +
|
| + return this.modeElements_[mode];
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * The ".com" key.
|
| + * @constructor
|
| + * @extends {BaseKey}
|
| + */
|
| +function DotComKey() {
|
| + this.modeElements_ = {};
|
| + this.cellType_ = 'nc';
|
| +}
|
| +
|
| +DotComKey.prototype = {
|
| + __proto__: BaseKey.prototype,
|
| +
|
| + /** @override */
|
| + makeDOM: function(mode) {
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + this.modeElements_[mode].className = 'key com';
|
| + addContent(this.modeElements_[mode], '.com');
|
| +
|
| + setupKeyEventHandlers(this, this.modeElements_[mode],
|
| + { 'up': function() {
|
| + sendKey('.');
|
| + sendKey('c');
|
| + sendKey('o');
|
| + sendKey('m');
|
| + }});
|
| +
|
| + return this.modeElements_[mode];
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * The key that hides the keyboard.
|
| + * @constructor
|
| + * @extends {BaseKey}
|
| + */
|
| +function HideKeyboardKey() {
|
| + this.modeElements_ = {};
|
| + this.cellType_ = 'nc';
|
| +}
|
| +
|
| +HideKeyboardKey.prototype = {
|
| + __proto__: BaseKey.prototype,
|
| +
|
| + /** @override */
|
| + makeDOM: function(mode) {
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + this.modeElements_[mode].className = 'key hide';
|
| + addContent(this.modeElements_[mode]);
|
| +
|
| + setupKeyEventHandlers(this, this.modeElements_[mode],
|
| + { 'down': function() { console.log('Hide the keyboard!'); } });
|
| +
|
| + return this.modeElements_[mode];
|
| + }
|
| +};
|
| +
|
| +/**
|
| + * A container for keys.
|
| + * @param {number} position The position of the row (0-3).
|
| + * @param {Array.<BaseKey>} keys The keys in the row.
|
| + * @constructor
|
| + */
|
| +function Row(position, keys) {
|
| + this.position_ = position;
|
| + this.keys_ = keys;
|
| + this.element_ = null;
|
| + this.modeElements_ = {};
|
| +}
|
| +
|
| +Row.prototype = {
|
| + /**
|
| + * Create the DOM elements for the row.
|
| + * @return {Element} The top-level DOM Element for the row.
|
| + */
|
| + makeDOM: function() {
|
| + this.element_ = document.createElement('div');
|
| + this.element_.className = 'row';
|
| + for (var i = 0; i < MODES.length; ++i) {
|
| + var mode = MODES[i];
|
| + this.modeElements_[mode] = document.createElement('div');
|
| + this.modeElements_[mode].style.display = 'none';
|
| + this.element_.appendChild(this.modeElements_[mode]);
|
| + }
|
| +
|
| + for (var j = 0; j < this.keys_.length; ++j) {
|
| + var key = this.keys_[j];
|
| + for (var i = 0; i < MODES.length; ++i) {
|
| + var keyDom = key.makeDOM(MODES[i]);
|
| + if (keyDom) {
|
| + this.modeElements_[MODES[i]].appendChild(keyDom);
|
| + }
|
| + }
|
| + }
|
| +
|
| + for (var i = 0; i < MODES.length; ++i) {
|
| + var clearingDiv = document.createElement('div');
|
| + clearingDiv.style.clear = 'both';
|
| + this.modeElements_[MODES[i]].appendChild(clearingDiv);
|
| + }
|
| +
|
| + return this.element_;
|
| + },
|
| +
|
| + /**
|
| + * Shows the given mode.
|
| + * @param {string} mode The mode to show.
|
| + */
|
| + showMode: function(mode) {
|
| + for (var i = 0; i < MODES.length; ++i) {
|
| + this.modeElements_[MODES[i]].style.display = 'none';
|
| + }
|
| + this.modeElements_[mode].style.display = '-webkit-box';
|
| + },
|
| +
|
| + /**
|
| + * Returns the size of keys this row contains.
|
| + * @return {number} The size of keys.
|
| + */
|
| + get length() {
|
| + return this.keys_.length;
|
| + }
|
| +};
|
|
|