Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / keyboard / resources / elements / kb-key-base.js
blobed6b527d7651959efe0c7da7893e201238addd8e
1 // Copyright 2014 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.
5 /**
6  * The long-press delay in milliseconds before long-press handler is
7  * invoked.
8  * @const
9  * @type {number}
10  */
11 var LONGPRESS_DELAY_MSEC = 500;
13 /**
14  * The maximum number of elements in one keyset rule.
15  * @const
16  * @type {number}
17  */
18 var MAXIMUM_NUM_OF_RULE_ELEMENTS = 3;
20 /**
21  * The minumum number of elements in one keyset rule.
22  * @const
23  * @type {number}
24  */
25 var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
27 /**
28  * The index of event type element in the splitted keyset rule.
29  * @const
30  * @type {number}
31  */
32 var EVENT_TYPE = 0;
34 /**
35  * The index of toKeyset element in the splitted keyset rule.
36  * @const
37  * @type {number}
38  */
39 var TO_KEYSET = 1;
41 /**
42  * The index of nextKeyset element in the splitted keyset rule.
43  * @const
44  * @type {number}
45  */
46 var NEXT_KEYSET = 2;
48 /**
49  * The index offset of toKeyset and nextKeyset elements in splitted keyset
50  * rule array and the array in keysetRules.
51  * @const
52  * @type {number}
53  */
54 var OFFSET = 1;
56 /**
57  * The minumum number of elements in one keyset rule.
58  * @const {number}
59  */
60 var MINIMUM_NUM_OF_RULE_ELEMENTS = 2;
62 Polymer('kb-key-base', {
63   repeat: false,
64   invert: false,
65   longPressTimer: null,
66   pointerId: undefined,
68   /**
69    * The keyset transition rules. It defines which keyset to transit to on
70    * which key events. It consists at most four rules (down, up, long, dbl).
71    * If no rule is defined for a key event, the event wont trigger a keyset
72    * change.
73    * @type {Object.<string, Array.<string>}
74    */
75   keysetRules: null,
77   ready: function() {
78     if (this.toKeyset) {
79       // Parsing keyset rules from toKeyset attribute string.
80       // An rule can be defined as: (down|up|long|dbl):keysetid[:keysetid]
81       // and each rule are separated by a semicolon. The first element
82       // defines the event this rule applies to. The second element defines
83       // what keyset to transit to after event received. The third optional
84       // element defines what keyset to transit to after a key is pressed in
85       // the new keyset. It is useful when you want to transit to a not
86       // locked keyset. For example, after transit to a upper case keyset,
87       // it may make sense to transit back to lower case after user typed
88       // any key at the upper case keyset.
89       var rules =
90           this.toKeyset.replace(/(\r\n|\n|\r| )/g, '').split(';');
91       this.keysetRules = {};
92       var self = this;
93       rules.forEach(function(element) {
94         if (element == '')
95           return;
96         var keyValues = element.split(':', MAXIMUM_NUM_OF_RULE_ELEMENTS);
97         if (keyValues.length < MINIMUM_NUM_OF_RULE_ELEMENTS) {
98           console.error('Invalid keyset rules: ' + element);
99           return;
100         }
101         self.keysetRules[keyValues[EVENT_TYPE]] = [keyValues[TO_KEYSET],
102             (keyValues[NEXT_KEYSET] ? keyValues[NEXT_KEYSET] : null)];
103       });
104     }
105   },
107   down: function(event) {
108     this.pointerId = event.pointerId;
109     var detail = this.populateDetails('down');
110     this.fire('key-down', detail);
111     this.longPressTimer = this.generateLongPressTimer();
112   },
113   out: function(event) {
114     this.classList.remove('active');
115     clearTimeout(this.longPressTimer);
116   },
117   up: function(event) {
118     this.generateKeyup();
119   },
121   /**
122    * Releases the pressed key programmatically and fires key-up event. This
123    * should be called if a second key is pressed while the first key is not
124    * released yet.
125    */
126   autoRelease: function() {
127     this.generateKeyup();
128   },
130   /**
131    * Drops the pressed key.
132    */
133   dropKey: function() {
134     this.classList.remove('active');
135     clearTimeout(this.longPressTimer);
136     this.pointerId = undefined;
137   },
139   /**
140    * Populates details for this key, and then fires a key-up event.
141    */
142   generateKeyup: function() {
143     if (this.pointerId === undefined)
144       return;
146     // Invalidates the pointerId so the subsequent pointerup event is a
147     // noop.
148     this.pointerId = undefined;
149     clearTimeout(this.longPressTimer);
150     var detail = this.populateDetails('up');
151     this.fire('key-up', detail);
152   },
154   /**
155    * Character value associated with the key. Typically, the value is a
156    * single character, but may be multi-character in cases like a ".com"
157    * button.
158    * @return {string}
159    */
160   get charValue() {
161     return this.invert ? this.hintText : (this.char || this.textContent);
162   },
164   /**
165    * Hint text value associated with the key. Typically, the value is a
166    * single character.
167    * @return {string}
168    */
169   get hintTextValue() {
170     return this.invert ? (this.char || this.textContent) : this.hintText;
171   },
173   /**
174    * Handles a swipe flick that originated from this key.
175    * @param {detail} The details of the swipe.
176    */
177   onFlick: function(detail) {
178     if (!(detail.direction & SwipeDirection.UP) || !this.hintTextValue)
179       return;
180     var typeDetails = {char: this.hintTextValue};
181     this.fire('type-key', typeDetails);
182   },
184   /**
185    * Returns a subset of the key attributes.
186    * @param {string} caller The id of the function which called
187    *     populateDetails.
188    */
189   populateDetails: function(caller) {
190     var detail = {
191       char: this.charValue,
192       toLayout: this.toLayout,
193       repeat: this.repeat
194     };
196     switch (caller) {
197       case ('up'):
198         if (this.keysetRules && this.keysetRules.up != undefined) {
199           detail.toKeyset = this.keysetRules.up[TO_KEYSET - OFFSET];
200           detail.nextKeyset = this.keysetRules.up[NEXT_KEYSET - OFFSET];
201         }
202         break;
203       case ('down'):
204         if (this.keysetRules && this.keysetRules.down != undefined) {
205           detail.toKeyset = this.keysetRules.down[TO_KEYSET - OFFSET];
206           detail.nextKeyset = this.keysetRules.down[NEXT_KEYSET - OFFSET];
207         }
208         break;
209       default:
210         break;
211     }
212     return detail;
213   },
215   generateLongPressTimer: function() {
216     return this.async(function() {
217       var detail = {
218         char: this.charValue,
219         hintText: this.hintTextValue
220       };
221       if (this.keysetRules && this.keysetRules.long != undefined) {
222         detail.toKeyset = this.keysetRules.long[TO_KEYSET - OFFSET];
223         detail.nextKeyset = this.keysetRules.long[NEXT_KEYSET - OFFSET];
224       }
225       this.fire('key-longpress', detail);
226     }, null, LONGPRESS_DELAY_MSEC);
227   },