- add sources.
[platform/framework/web/crosswalk.git] / src / ui / keyboard / resources / elements / kb-shift-key.html
1 <!--
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.
5   -->
6
7 <polymer-element name="kb-shift-key"
8     attributes="lowerCaseKeysetId upperCaseKeysetId"
9     class="shift dark" char="Shift" on-pointerout="out" extends="kb-key">
10   <script>
11     (function () {
12
13       /**
14        * The possible states of the shift key.
15        * Unlocked is the default state. Locked for capslocked, pressed is a
16        * key-down and tapped for a key-down followed by an immediate key-up.
17        * @const
18        * @type {Enum}
19        */
20       var KEY_STATES = {
21         PRESSED: "pressed", // Key-down on shift key.
22         LOCKED: "locked", // Key is capslocked.
23         UNLOCKED: "unlocked", // Default state.
24         TAPPED: "tapped", // Key-down followed by key-up.
25         CHORDING: "chording" // Key-down followed by other keys.
26       };
27
28       /**
29        * The pointerdown event on shiftkey that may eventually trigger chording
30        * state. pointerId and eventTarget are the two fields that is used now.
31        * @type {PointerEvent}
32        */
33       var enterChordingEvent = undefined;
34
35       /**
36        * Uses a closure to define one long press timer among all shift keys
37        * regardless of the layout they are in.
38        * @type {function}
39        */
40       var shiftLongPressTimer = undefined;
41
42       /**
43        * The current state of the shift key.
44        * @type {Enum}
45        */
46       var state = KEY_STATES.UNLOCKED;
47
48       Polymer('kb-shift-key', {
49         /**
50          * Defines how capslock effects keyset transition. We always transition
51          * from the lowerCaseKeysetId to the upperCaseKeysetId if capslock is
52          * on.
53          * @type {string}
54          */
55         lowerCaseKeysetId: 'lower',
56         upperCaseKeysetId: 'upper',
57
58         up: function(event) {
59           if (state == KEY_STATES.CHORDING &&
60               event.pointerId != enterChordingEvent.pointerId) {
61             // Disables all other pointer events on shift keys when chording.
62             return;
63           }
64           switch (state) {
65             case KEY_STATES.PRESSED:
66               state = KEY_STATES.TAPPED;
67               break;
68             case KEY_STATES.CHORDING:
69               // Leaves chording only if the pointer that triggered it is
70               // released.
71               state = KEY_STATES.UNLOCKED;
72               break;
73             default:
74               break;
75           }
76           // When releasing the shift key, it is not the same shift key that was
77           // pressed. Updates the pointerId of the releasing shift key to make
78           // sure key-up event fires correctly in kb-key-base.
79           this.pointerId = enterChordingEvent.pointerId;
80           this.super([event]);
81         },
82
83         out: function(event) {
84           // Sliding off the shift key while chording is treated as a key-up.
85           // Note that we switch to a new keyset on shift keydown, and a finger
86           // movement on the new shift key will trigger this function being
87           // called on the old shift key. We should not end chording in that
88           // case.
89           if (state == KEY_STATES.CHORDING &&
90               event.pointerId == enterChordingEvent.pointerId &&
91               event.target != enterChordingEvent.target) {
92             state = KEY_STATES.UNLOCKED;
93             var detail = this.populateDetails('out');
94             this.fire("key-out", detail);
95           }
96         },
97
98         down: function(event) {
99           // First transition state so that populateDetails generates
100           // correct data.
101           switch (state) {
102             case KEY_STATES.UNLOCKED:
103               state = KEY_STATES.PRESSED;
104               break;
105             case KEY_STATES.TAPPED:
106             case KEY_STATES.LOCKED:
107               state = KEY_STATES.UNLOCKED;
108               break;
109             case KEY_STATES.PRESSED:
110             case KEY_STATES.CHORDING:
111               // We pressed another shift key at the same time,
112               // so ignore second press.
113               return;
114             default:
115               console.error("Undefined shift key state: " + state);
116               break;
117           }
118           enterChordingEvent = event;
119           // Trigger parent behaviour.
120           this.super([event]);
121           this.fire('enable-sel');
122           // Populate double click transition details.
123           var detail = {};
124           detail.char = this.char || this.textContent;
125           detail.toKeyset = this.upperCaseKeysetId;
126           detail.nextKeyset = undefined;
127           detail.callback = this.onDoubleClick;
128           this.fire('enable-dbl', detail);
129         },
130
131         generateLongPressTimer: function() {
132           return this.asyncMethod(function() {
133             var detail = this.populateDetails();
134             if (state == KEY_STATES.LOCKED) {
135               // We don't care about the longpress if we are already
136               // capitalized.
137               return;
138             } else {
139               state = KEY_STATES.LOCKED;
140               detail.toKeyset = this.upperCaseKeysetId;
141               detail.nextKeyset = undefined;
142             }
143             this.fire('key-longpress', detail);
144           }, null, LONGPRESS_DELAY_MSEC);
145         },
146
147         // @return Whether the shift modifier is currently active.
148         isActive: function() {
149           return state != KEY_STATES.UNLOCKED;
150         },
151
152         /**
153          * Callback function for when a double click is triggered.
154          */
155         onDoubleClick: function() {
156           state = KEY_STATES.LOCKED;
157         },
158
159         /**
160          * Notifies shift key that a non-control key was pressed down.
161          * A control key is defined as one of shift, control or alt.
162          */
163         onNonControlKeyDown: function() {
164           switch (state) {
165             case (KEY_STATES.PRESSED):
166               state = KEY_STATES.CHORDING;
167               // Disable longpress timer.
168               clearTimeout(shiftLongPressTimer);
169               break;
170             default:
171               break;
172           }
173         },
174
175         /**
176          * Notifies key that a non-control keyed was typed.
177          * A control key is defined as one of shift, control or alt.
178          */
179         onNonControlKeyTyped: function() {
180           if (state == KEY_STATES.TAPPED)
181             state = KEY_STATES.UNLOCKED;
182         },
183
184         /**
185          * Callback function for when a space is pressed after punctuation.
186          * @return {Object} The keyset transitions the keyboard should make.
187          */
188         onSpaceAfterPunctuation: function() {
189            var detail = {};
190            detail.toKeyset = this.upperCaseKeysetId;
191            detail.nextKeyset = this.lowerCaseKeysetId;
192            state = KEY_STATES.TAPPED;
193            return detail;
194         },
195
196         populateDetails: function(caller) {
197           var detail = this.super([caller]);
198           switch(state) {
199             case(KEY_STATES.LOCKED):
200               detail.toKeyset = this.upperCaseKeysetId;
201               break;
202             case(KEY_STATES.UNLOCKED):
203               detail.toKeyset = this.lowerCaseKeysetId;
204               break;
205             case(KEY_STATES.PRESSED):
206               detail.toKeyset = this.upperCaseKeysetId;
207               break;
208             case(KEY_STATES.TAPPED):
209               detail.toKeyset = this.upperCaseKeysetId;
210               detail.nextKeyset = this.lowerCaseKeysetId;
211               break;
212             case(KEY_STATES.CHORDING):
213               detail.toKeyset = this.lowerCaseKeysetId;
214               break;
215             default:
216               break;
217           }
218           return detail;
219         },
220
221         /**
222          *  Resets the shift key state.
223          */
224         reset: function() {
225           state = KEY_STATES.UNLOCKED;
226         },
227
228         /**
229          * Overrides longPressTimer for the shift key.
230          */
231         get longPressTimer() {
232           return shiftLongPressTimer;
233         },
234
235         set longPressTimer(timer) {
236           shiftLongPressTimer = timer;
237         },
238
239         get state() {
240           return state;
241         },
242
243         get textKeyset() {
244           switch (state) {
245             case KEY_STATES.UNLOCKED:
246               return this.lowerCaseKeysetId;
247             default:
248               return this.upperCaseKeysetId;
249           }
250         },
251       });
252     })();
253   </script>
254 </polymer-element>