Chromium Code Reviews| Index: chrome/browser/resources/keyboard/common.js |
| diff --git a/chrome/browser/resources/keyboard/common.js b/chrome/browser/resources/keyboard/common.js |
| index a3dff78eca727ce3e482ba347865a5b989f48d01..54bd4b28dba65b4887afa36e62a2814ea2d08c33 100644 |
| --- a/chrome/browser/resources/keyboard/common.js |
| +++ b/chrome/browser/resources/keyboard/common.js |
| @@ -47,6 +47,18 @@ var REPEAT_DELAY_MSEC = 500; |
| var REPEAT_INTERVAL_MSEC = 50; |
| /** |
| + * The keyboard layout name currently in use. |
| + * @type {string} |
| + */ |
| +var currentKeyboardLayout = 'us'; |
| + |
| +/** |
| + * The popup keyboard layout name currently in use. |
| + * @type {string} |
| + */ |
| +var currentPopupName = ''; |
| + |
| +/** |
| * A structure to track the currently repeating key on the keyboard. |
| */ |
| var repeatKey = { |
| @@ -81,6 +93,31 @@ var repeatKey = { |
| }; |
| /** |
| + * An array to track the currently touched keys on the popup keyboard. |
| + */ |
| +var touchedKeys = []; |
| + |
| +/** |
| + * Set the keyboard mode. |
| + * @param {string} mode The new mode. |
| + * @return {void} |
| + */ |
| +function setMode(mode) { |
| + var rows = KEYBOARDS[currentKeyboardLayout]['rows']; |
| + for (var i = 0; i < rows.length; ++i) { |
| + rows[i].showMode(mode); |
| + } |
| + |
| + if (!currentPopupName) { |
| + return; |
| + } |
| + var popupRows = KEYBOARDS[currentPopupName]['rows']; |
| + for (var i = 0; i < popupRows.length; ++i) { |
| + popupRows[i].showMode(mode); |
| + } |
| +} |
| + |
| +/** |
| * Transition the mode according to the given transition. |
| * @param {string} transition The transition to take. |
| * @return {void} |
| @@ -214,8 +251,14 @@ function setupKeyEventHandlers(key, element, handlers) { |
| } |
| if (keyLongHandler) { |
| + // Copy the current state of event because |evt| can be modified before |
| + // |keyLongHandler| is called. |
|
bryeung
2011/09/08 19:22:35
Where is the event being modified?
Also, can we c
mazda
2011/09/12 14:33:48
I'm not sure where it is modified, but evt.current
bryeung
2011/09/13 23:53:04
Sorry. I think my use of the word "keys" was a po
mazda
2011/09/16 13:16:37
Yes, that's fine. But if we use keyLongHandler for
bryeung
2011/09/19 15:05:09
I don't see that change in this patch. Do you nee
|
| + var evt2 = {}; |
| + for (var name in evt) { |
| + evt2[name] = evt[name]; |
| + } |
| key.longPressTimer = setTimeout(function() { |
| - keyLongHandler(evt), |
| + keyLongHandler(evt2), |
| clearTimeout(key.longPressTimer); |
| delete key.longPressTimer; |
| key.pressed = false; |
| @@ -252,6 +295,9 @@ function setupKeyEventHandlers(key, element, handlers) { |
| }; |
| var outHandler = function(evt) { |
| + if (evt.target != evt.currentTarget) { |
|
bryeung
2011/09/08 19:22:35
Why is this needed now?
mazda
2011/09/12 14:33:48
This kind of check should have been in the CL that
bryeung
2011/09/13 23:53:04
Thank you for the explanation. I think maybe we s
mazda
2011/09/16 13:16:37
Added a comment.
|
| + return; |
| + } |
| // Reset key press state if the point goes out of the element. |
| key.pressed = false; |
| // Reset long-press timer. |
| @@ -285,12 +331,123 @@ function sendKeyFunction(key) { |
| } |
| /** |
| + * Dispatch custom events to the elements at the touch points. |
|
bryeung
2011/09/08 19:22:35
It's not clear to me why we need to make custom ev
mazda
2011/09/12 14:33:48
touchmove and touchend events are not sent to the
bryeung
2011/09/13 23:53:04
Is there a reason why we can't simulate regular ev
mazda
2011/09/16 13:16:37
touchmove and touchend events are sent to the elem
|
| + * touchpointmove events are dispatched responding to a touchmove and |
| + * touchpointend events responding to a touchend event respectively. |
| + * @param {UIEvent} evt The touch event that contains touch points information. |
| + * @return {void} |
| + */ |
| +function dispatchTouchPointEvent(evt) { |
| + var type = null; |
| + var touches = null; |
| + if (evt.type == 'touchmove') { |
| + type = 'touchpointmove'; |
| + touches = evt.touches; |
| + } else if (evt.type == 'touchend') { |
| + type = 'touchpointend'; |
| + touches = evt.changedTouches; |
| + } else { |
| + return; |
| + } |
| + |
| + for (var i = 0; i < touches.length; ++i) { |
| + var dispatchedEvent = document.createEvent('Event'); |
| + dispatchedEvent.initEvent(type, true, false); |
| + var touch = touches[i]; |
| + var key = document.elementFromPoint(touch.screenX, touch.screenY); |
| + if (key) { |
| + key.dispatchEvent(dispatchedEvent); |
| + } |
| + } |
| +} |
| + |
| +/** |
| + * Handle a touch move event on the key to make changes to the popup keyboard. |
| + * @param {UIEvent} evt The UI event which triggered the touch move. |
| + * @return {void} |
| +*/ |
| +function trackTouchMoveForPopup(evt) { |
| + var previous = touchedKeys; |
| + touchedKeys = []; |
| + dispatchTouchPointEvent(evt); |
| + for (var i = 0; i < previous.length; ++i) { |
| + if (touchedKeys.indexOf(previous[i]) == -1) { |
| + previous[i].classList.remove('highlighted'); |
| + } |
| + } |
| + for (var i = 0; i < touchedKeys.length; ++i) { |
| + touchedKeys[i].classList.add('highlighted'); |
| + } |
| +} |
| + |
| +/** |
| + * Handle a touch end event on the key to make changes to the popup keyboard. |
| + * @param {UIEvent} evt The UI event which triggered the touch end. |
| + * @return {void} |
| +*/ |
| +function trackTouchEndForPopup(evt) { |
| + for (var i = 0; i < touchedKeys.length; ++i) { |
| + touchedKeys[i].classList.remove('highlighted'); |
| + } |
| + dispatchTouchPointEvent(evt); |
| + hidePopupKeyboard(); |
| + |
| + touchedKeys = []; |
| + evt.target.removeEventListener('touchmove', trackTouchMoveForPopup); |
| + evt.target.removeEventListener('touchend', trackTouchEndForPopup); |
| +} |
| + |
| +/** |
| * Show the popup keyboard. |
| * @param {string} name The name of the popup keyboard. |
| + * @return {void} |
| */ |
| -function showPopupKeyboard(name) { |
| - // TODO(mazda): Implement this function. |
| - console.warn('Popup keyboard is not implemented yet.'); |
| +function showPopupKeyboard(name, evt) { |
| + var popupDiv = document.getElementById('popup'); |
| + if (popupDiv.style.visibility == 'visible') { |
| + return; |
| + } |
| + |
| + // Reinitialize the rows of the popup keyboard |
| + if (currentPopupName != name) { |
| + while (popupDiv.firstChild) { |
| + popupDiv.removeChild(popupDiv.firstChild); |
| + } |
| + if (currentPopupName in KEYBOARDS) { |
| + delete KEYBOARDS[currentPopupName].rows; |
| + } |
| + initRows(name, popupDiv, true); |
| + currentPopupName = name; |
| + } |
| + |
| + // Set the mode of the popup keyboard |
| + var popupRows = KEYBOARDS[currentPopupName]['rows']; |
| + for (var i = 0; i < popupRows.length; ++i) { |
| + popupRows[i].showMode(currentMode); |
| + } |
| + |
| + // Calculate the size of popup keyboard based on the size of the key. |
| + var keyElement = evt.currentTarget; |
| + var keyboard = KEYBOARDS[name]; |
| + var rows = keyboard['definition']; |
| + var height = keyElement.offsetHeight * rows.length; |
| + var aspect = keyboard['aspect']; |
| + var width = aspect * height; |
| + popupDiv.style.width = width + 'px'; |
| + popupDiv.style.height = height + 'px'; |
| + |
| + // Place the popup keyboard above the key |
| + var rect = keyElement.getBoundingClientRect(); |
| + var left = (rect.left + rect.right) / 2 - width / 2; |
| + left = Math.min(Math.max(left, 0), window.innerWidth - width); |
| + var top = rect.top - height; |
| + top = Math.min(Math.max(top, 0), window.innerHeight - height); |
| + popupDiv.style.left = left + 'px'; |
| + popupDiv.style.top = top + 'px'; |
| + popupDiv.style.visibility = 'visible'; |
| + |
| + keyElement.addEventListener('touchmove', trackTouchMoveForPopup); |
| + keyElement.addEventListener('touchend', trackTouchEndForPopup); |
| } |
| /** |
| @@ -299,12 +456,21 @@ function showPopupKeyboard(name) { |
| * @return {function()} A function which calls showPopupKeyboard(name). |
| */ |
| function showPopupKeyboardFunction(name) { |
| - return function () { |
| - showPopupKeyboard(name); |
| + return function (evt) { |
| + showPopupKeyboard(name, evt); |
| }; |
| } |
| /** |
| + * Hide the popup keyboard. |
| + * @return {void} |
| + */ |
| +function hidePopupKeyboard() { |
| + var popupDiv = document.getElementById('popup'); |
| + popupDiv.style.visibility = 'hidden'; |
| +} |
| + |
| +/** |
| * 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. |
| @@ -317,10 +483,20 @@ function Character(display, id) { |
| /** |
| * Convenience function to make the keyboard data more readable. |
| - * @param {string} display Both the display and id for the created Character. |
| + * If |opt_id| is omitted, |display| is used as the id. |
| + * @param {string} display The display for the created Character. |
| + * @param {string} opt_id The id for the created Character. |
| + * @param {string} opt_popupName The popup keyboard name for this character. |
| + * @return {Object} An object that contains a Character and the popup keyboard |
| + * name. |
| */ |
| -function C(display) { |
| - return new Character(display, display); |
| +function C(display, opt_id, opt_popupName) { |
| + var id = opt_id || display; |
| + var result = { character: new Character(display, id)}; |
| + if (opt_popupName) { |
| + result['popupName'] = opt_popupName; |
| + } |
| + return result; |
| } |
| /** |
| @@ -409,15 +585,22 @@ BaseKey.prototype = { |
| * @constructor |
| * @extends {BaseKey} |
| */ |
| -function Key(key, shift, num, symbol) { |
| +function Key(key, shift, num, symbol, opt_className) { |
| this.modeElements_ = {}; |
| this.cellType_ = ''; |
| + this.className_ = opt_className || ""; |
| this.modes_ = {}; |
| - this.modes_[KEY_MODE] = key; |
| - this.modes_[SHIFT_MODE] = shift; |
| - this.modes_[NUMBER_MODE] = num; |
| - this.modes_[SYMBOL_MODE] = symbol; |
| + this.modes_[KEY_MODE] = key ? key.character : null; |
| + this.modes_[SHIFT_MODE] = shift ? shift.character : null; |
| + this.modes_[NUMBER_MODE] = num ? num.character : null; |
| + this.modes_[SYMBOL_MODE] = symbol ? symbol.character : null; |
| + |
| + this.popupNames_ = {}; |
| + this.popupNames_[KEY_MODE] = key ? key.popupName : null; |
| + this.popupNames_[SHIFT_MODE] = shift ? shift.popupName : null; |
| + this.popupNames_[NUMBER_MODE] = num ? num.popupName : null; |
| + this.popupNames_[SYMBOL_MODE] = symbol ? symbol.popupName : null; |
| } |
| Key.prototype = { |
| @@ -430,16 +613,36 @@ Key.prototype = { |
| } |
| this.modeElements_[mode] = document.createElement('div'); |
| - this.modeElements_[mode].className = 'key'; |
| - addContent(this.modeElements_[mode], this.modes_[mode].display); |
| - |
| - // TODO(mazda): Set the long-press handler only if the key has characters |
| - // to show on the popup keyboard. |
| - setupKeyEventHandlers(this, this.modeElements_[mode], |
| - { 'up': sendKeyFunction(this.modes_[mode].keyIdentifier), |
| - 'long': showPopupKeyboardFunction('') }); |
| + var element = this.modeElements_[mode]; |
| + element.className = 'key'; |
| + if (this.className_) { |
| + element.classList.add(this.className_); |
| + } |
| - return this.modeElements_[mode]; |
| + addContent(element, this.modes_[mode].display); |
| + |
| + var upHandler = sendKeyFunction(this.modes_[mode].keyIdentifier); |
| + if (this.className_ == 'popupkey') { |
|
bryeung
2011/09/08 19:22:35
I don't like giving the class name this semantic v
mazda
2011/09/12 14:33:48
popupNames are added for the keys that invokes the
bryeung
2011/09/13 23:53:04
I like this much better. Thank you.
|
| + // Add handlers for keys on the popup keyboard |
| + element.addEventListener('touchpointmove', function(evt) { |
| + touchedKeys.push(element); |
| + }); |
| + element.addEventListener('touchpointend', upHandler); |
| + element.addEventListener('mouseup', upHandler); |
| + element.addEventListener('mouseover', function(evt) { |
| + element.classList.add('highlighted'); |
| + }); |
| + element.addEventListener('mouseout', function(evt) { |
| + element.classList.remove('highlighted'); |
| + }); |
| + } else { |
| + var longHandler = this.popupNames_[mode] ? |
| + showPopupKeyboardFunction(this.popupNames_[mode]) : null; |
| + setupKeyEventHandlers(this, element, |
| + { 'up': upHandler, |
| + 'long': longHandler }); |
| + } |
| + return element; |
| } |
| }; |
| @@ -715,4 +918,12 @@ Row.prototype = { |
| } |
| 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; |
| + } |
| }; |