2 -- Copyright 2013 The Chromium Authors. All rights reserved.
3 -- Use of this source code is governed by a BSD-style license that can be
4 -- found in the LICENSE file.
7 <polymer-element name="kb-key-base"
8 on-pointerdown="down" on-pointerup="up" on-pointerout="out"
9 attributes="char invert repeat hintText toKeyset toLayout">
12 * The long-press delay in milliseconds before long-press handler is
17 var LONGPRESS_DELAY_MSEC = 500;
20 * The maximum number of elements in one keyset rule.
24 var MAXIMUM_NUM_OF_RULE_ELEMENTS = 3;
27 * The minumum number of elements in one keyset rule.
31 var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
34 * The index of event type element in the splitted keyset rule.
41 * The index of toKeyset element in the splitted keyset rule.
48 * The index of nextKeyset element in the splitted keyset rule.
55 * The index offset of toKeyset and nextKeyset elements in splitted keyset
56 * rule array and the array in keysetRules.
63 * The minumum number of elements in one keyset rule.
66 var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
68 Polymer('kb-key-base', {
75 * The keyset transition rules. It defines which keyset to transit to on
76 * which key events. It consists at most four rules (down, up, long, dbl).
77 * If no rule is defined for a key event, the event wont trigger a keyset
79 * @type {Object.<string, Array.<string>}
85 // Parsing keyset rules from toKeyset attribute string.
86 // An rule can be defined as: (down|up|long|dbl):keysetid[:keysetid]
87 // and each rule are separated by a semicolon. The first element
88 // defines the event this rule applies to. The second element defines
89 // what keyset to transit to after event received. The third optional
90 // element defines what keyset to transit to after a key is pressed in
91 // the new keyset. It is useful when you want to transit to a not
92 // locked keyset. For example, after transit to a upper case keyset,
93 // it may make sense to transit back to lower case after user typed
94 // any key at the upper case keyset.
96 this.toKeyset.replace(/(\r\n|\n|\r| )/g, '').split(';');
97 this.keysetRules = {};
99 rules.forEach(function(element) {
102 var keyValues = element.split(':', MAXIMUM_NUM_OF_RULE_ELEMENTS);
103 if (keyValues.length < MINIMUM_NUM_OF_RULE_ELEMENTS) {
104 console.error('Invalid keyset rules: ' + element);
107 self.keysetRules[keyValues[EVENT_TYPE]] = [keyValues[TO_KEYSET],
108 (keyValues[NEXT_KEYSET] ? keyValues[NEXT_KEYSET] : null)];
113 down: function(event) {
114 this.pointerId = event.pointerId;
115 var detail = this.populateDetails('down');
116 this.fire('key-down', detail);
117 this.longPressTimer = this.generateLongPressTimer();
119 out: function(event) {
120 this.classList.remove('active');
121 clearTimeout(this.longPressTimer);
123 up: function(event) {
124 this.generateKeyup();
128 * Releases the pressed key programmatically and fires key-up event. This
129 * should be called if a second key is pressed while the first key is not
132 autoRelease: function() {
133 this.generateKeyup();
137 * Drops the pressed key.
139 dropKey: function() {
140 this.classList.remove('active');
141 clearTimeout(this.longPressTimer);
142 this.pointerId = undefined;
146 * Populates details for this key, and then fires a key-up event.
148 generateKeyup: function() {
149 if (this.pointerId === undefined)
152 // Invalidates the pointerId so the subsequent pointerup event is a
154 this.pointerId = undefined;
155 clearTimeout(this.longPressTimer);
156 var detail = this.populateDetails('up');
157 this.fire('key-up', detail);
161 * Character value associated with the key. Typically, the value is a
162 * single character, but may be multi-character in cases like a ".com"
167 return this.invert ? this.hintText : (this.char || this.textContent);
170 /* Hint text value associated with the key. Typically, the value is a
174 get hintTextValue() {
175 return this.invert ? (this.char || this.textContent) : this.hintText;
179 * Returns a subset of the key attributes.
180 * @param {string} caller The id of the function which called
183 populateDetails: function(caller) {
185 char: this.charValue,
186 toLayout: this.toLayout,
192 if (this.keysetRules && this.keysetRules.up != undefined) {
193 detail.toKeyset = this.keysetRules.up[TO_KEYSET - OFFSET];
194 detail.nextKeyset = this.keysetRules.up[NEXT_KEYSET - OFFSET];
198 if (this.keysetRules && this.keysetRules.down != undefined) {
199 detail.toKeyset = this.keysetRules.down[TO_KEYSET - OFFSET];
200 detail.nextKeyset = this.keysetRules.down[NEXT_KEYSET - OFFSET];
209 generateLongPressTimer: function() {
210 return this.asyncMethod(function() {
212 char: this.charValue,
213 hintText: this.hintTextValue
215 if (this.keysetRules && this.keysetRules.long != undefined) {
216 detail.toKeyset = this.keysetRules.long[TO_KEYSET - OFFSET];
217 detail.nextKeyset = this.keysetRules.long[NEXT_KEYSET - OFFSET];
219 this.fire('key-longpress', detail);
220 }, null, LONGPRESS_DELAY_MSEC);