-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
text_support.js
355 lines (298 loc) · 10.4 KB
/
text_support.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/**
@module ember
*/
import {
get,
set,
Mixin
} from 'ember-metal';
import { TargetActionSupport } from 'ember-runtime';
const KEY_EVENTS = {
13: 'insertNewline',
27: 'cancel'
};
/**
`TextSupport` is a shared mixin used by both `Ember.TextField` and
`Ember.TextArea`. `TextSupport` adds a number of methods that allow you to
specify a controller action to invoke when a certain event is fired on your
text field or textarea. The specified controller action would get the current
value of the field passed in as the only argument unless the value of
the field is empty. In that case, the instance of the field itself is passed
in as the only argument.
Let's use the pressing of the escape key as an example. If you wanted to
invoke a controller action when a user presses the escape key while on your
field, you would use the `escape-press` attribute on your field like so:
```handlebars
{{! application.hbs}}
{{input escape-press='alertUser'}}
```
```javascript
App = Ember.Application.create();
App.ApplicationController = Ember.Controller.extend({
actions: {
alertUser: function ( currentValue ) {
alert( 'escape pressed, current value: ' + currentValue );
}
}
});
```
The following chart is a visual representation of what takes place when the
escape key is pressed in this scenario:
```
The Template
+---------------------------+
| |
| escape-press='alertUser' |
| | TextSupport Mixin
+----+----------------------+ +-------------------------------+
| | cancel method |
| escape button pressed | |
+-------------------------------> | checks for the `escape-press` |
| attribute and pulls out the |
+-------------------------------+ | `alertUser` value |
| action name 'alertUser' +-------------------------------+
| sent to controller
v
Controller
+------------------------------------------ +
| |
| actions: { |
| alertUser: function( currentValue ){ |
| alert( 'the esc key was pressed!' ) |
| } |
| } |
| |
+-------------------------------------------+
```
Here are the events that we currently support along with the name of the
attribute you would need to use on your field. To reiterate, you would use the
attribute name like so:
```handlebars
{{input attribute-name='controllerAction'}}
```
```
+--------------------+----------------+
| | |
| event | attribute name |
+--------------------+----------------+
| new line inserted | insert-newline |
| | |
| enter key pressed | insert-newline |
| | |
| cancel key pressed | escape-press |
| | |
| focusin | focus-in |
| | |
| focusout | focus-out |
| | |
| keypress | key-press |
| | |
| keyup | key-up |
| | |
| keydown | key-down |
+--------------------+----------------+
```
@class TextSupport
@namespace Ember
@uses Ember.TargetActionSupport
@extends Mixin
@private
*/
export default Mixin.create(TargetActionSupport, {
value: '',
attributeBindings: [
'autocapitalize',
'autocorrect',
'autofocus',
'disabled',
'form',
'maxlength',
'minlength',
'placeholder',
'readonly',
'required',
'selectionDirection',
'spellcheck',
'tabindex',
'title'
],
placeholder: null,
disabled: false,
maxlength: null,
init() {
this._super(...arguments);
this.on('paste', this, this._elementValueDidChange);
this.on('cut', this, this._elementValueDidChange);
this.on('input', this, this._elementValueDidChange);
},
/**
The action to be sent when the user presses the return key.
This is similar to the `{{action}}` helper, but is fired when
the user presses the return key when editing a text field, and sends
the value of the field as the context.
@property action
@type String
@default null
@private
*/
action: null,
/**
The event that should send the action.
Options are:
* `enter`: the user pressed enter
* `keyPress`: the user pressed a key
@property onEvent
@type String
@default enter
@private
*/
onEvent: 'enter',
/**
Whether the `keyUp` event that triggers an `action` to be sent continues
propagating to other views.
By default, when the user presses the return key on their keyboard and
the text field has an `action` set, the action will be sent to the view's
controller and the key event will stop propagating.
If you would like parent views to receive the `keyUp` event even after an
action has been dispatched, set `bubbles` to true.
@property bubbles
@type Boolean
@default false
@private
*/
bubbles: false,
interpretKeyEvents(event) {
let map = KEY_EVENTS;
let method = map[event.keyCode];
this._elementValueDidChange();
if (method) { return this[method](event); }
},
_elementValueDidChange() {
set(this, 'value', this.element.value);
},
change(event) {
this._elementValueDidChange(event);
},
/**
Allows you to specify a controller action to invoke when either the `enter`
key is pressed or, in the case of the field being a textarea, when a newline
is inserted. To use this method, give your field an `insert-newline`
attribute. The value of that attribute should be the name of the action
in your controller that you wish to invoke.
For an example on how to use the `insert-newline` attribute, please
reference the example near the top of this file.
@method insertNewline
@param {Event} event
@private
*/
insertNewline(event) {
sendAction('enter', this, event);
sendAction('insert-newline', this, event);
},
/**
Allows you to specify a controller action to invoke when the escape button
is pressed. To use this method, give your field an `escape-press`
attribute. The value of that attribute should be the name of the action
in your controller that you wish to invoke.
For an example on how to use the `escape-press` attribute, please reference
the example near the top of this file.
@method cancel
@param {Event} event
@private
*/
cancel(event) {
sendAction('escape-press', this, event);
},
/**
Allows you to specify a controller action to invoke when a field receives
focus. To use this method, give your field a `focus-in` attribute. The value
of that attribute should be the name of the action in your controller
that you wish to invoke.
For an example on how to use the `focus-in` attribute, please reference the
example near the top of this file.
@method focusIn
@param {Event} event
@private
*/
focusIn(event) {
sendAction('focus-in', this, event);
},
/**
Allows you to specify a controller action to invoke when a field loses
focus. To use this method, give your field a `focus-out` attribute. The value
of that attribute should be the name of the action in your controller
that you wish to invoke.
For an example on how to use the `focus-out` attribute, please reference the
example near the top of this file.
@method focusOut
@param {Event} event
@private
*/
focusOut(event) {
this._elementValueDidChange(event);
sendAction('focus-out', this, event);
},
/**
Allows you to specify a controller action to invoke when a key is pressed.
To use this method, give your field a `key-press` attribute. The value of
that attribute should be the name of the action in your controller you
that wish to invoke.
For an example on how to use the `key-press` attribute, please reference the
example near the top of this file.
@method keyPress
@param {Event} event
@private
*/
keyPress(event) {
sendAction('key-press', this, event);
},
/**
Allows you to specify a controller action to invoke when a key-up event is
fired. To use this method, give your field a `key-up` attribute. The value
of that attribute should be the name of the action in your controller
that you wish to invoke.
For an example on how to use the `key-up` attribute, please reference the
example near the top of this file.
@method keyUp
@param {Event} event
@private
*/
keyUp(event) {
this.interpretKeyEvents(event);
this.sendAction('key-up', get(this, 'value'), event);
},
/**
Allows you to specify a controller action to invoke when a key-down event is
fired. To use this method, give your field a `key-down` attribute. The value
of that attribute should be the name of the action in your controller that
you wish to invoke.
For an example on how to use the `key-down` attribute, please reference the
example near the top of this file.
@method keyDown
@param {Event} event
@private
*/
keyDown(event) {
this.sendAction('key-down', get(this, 'value'), event);
}
});
// In principle, this shouldn't be necessary, but the legacy
// sendAction semantics for TextField are different from
// the component semantics so this method normalizes them.
function sendAction(eventName, view, event) {
let action = get(view, `attrs.${eventName}`) || get(view, eventName);
let on = get(view, 'onEvent');
let value = get(view, 'value');
// back-compat support for keyPress as an event name even though
// it's also a method name that consumes the event (and therefore
// incompatible with sendAction semantics).
if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) {
view.sendAction('action', value);
}
view.sendAction(eventName, value);
if (action || on === eventName) {
if (!get(view, 'bubbles')) {
event.stopPropagation();
}
}
}