kea-rails 2.0.0.pre.alpha9 → 2.0.0.pre.alpha10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dfd428a9d60b70ebc40f6ab8e346f76050be3be2
4
- data.tar.gz: 85576cc5db899c936a8e7a040c5ff12a70f66c0f
3
+ metadata.gz: eb3b31ed74e896c174cb54a09cdc2a93ac5ee4e3
4
+ data.tar.gz: 5b692d4a6acc81b6e0393e24a4b2cf101e2196fc
5
5
  SHA512:
6
- metadata.gz: 09b69f5b315a2fc1b4ab967bf55472cecf37291612b0ab148ebd6f269f2956f15526f2abea46b3997c584b1a48ffc47d07876524721bf90933fa45a067eab929
7
- data.tar.gz: 6ac017b70151502759c5751d9a9a130f47ba9f8e6a2c3c5ecc574cb49af2e238f0e0a9955c66ee415ef618388677ed3407cd48d19d519422b2a9f6737b84186d
6
+ metadata.gz: 181e188768920beff23e2d02ff259632e2068f0433647a119f31e339f74a124f56740dafd161d8348a2aecace564d6b66892480d49b06ca02b0d797cf26b06f6
7
+ data.tar.gz: ffec861f77ad0135edbdaef2ee258da73bd676025d32db1e91b69e24ca640842b522d8b5ef2185893370f5a83b649ed235a9aeb5c95913c2c6f930b6325ee153
@@ -17,6 +17,8 @@ class Kea::InstallGenerator < Rails::Generators::Base
17
17
  empty_directory namespaced_path("app/assets/javascripts", "services")
18
18
  create_file namespaced_path("app/assets/javascripts", "services/.keep")
19
19
  empty_directory namespaced_path("app/assets/javascripts", "viewmodels")
20
+ empty_directory namespaced_path("app/assets/javascripts", "components")
21
+ create_file namespaced_path("app/assets/javascripts", "components/.keep")
20
22
  empty_directory namespaced_path("app/assets/javascripts", "sherlock")
21
23
  create_file namespaced_path("app/assets/javascripts", "sherlock/.keep")
22
24
  end
@@ -42,6 +44,7 @@ class Kea::InstallGenerator < Rails::Generators::Base
42
44
  //= require_directory ./services
43
45
  //= require ./viewmodels/main
44
46
  //= require_directory ./viewmodels
47
+ //= require_directory ./components
45
48
 
46
49
  //= require_directory ./sherlock
47
50
 
@@ -51,7 +51,7 @@ class Kea::ModelGenerator < Rails::Generators::NamedBase
51
51
  unserializable_attributes << attribute if @klass.attribute_names.include?(attribute)
52
52
  end
53
53
 
54
- attribute_initializers << "this.unserializable_attributes(#{unserializable_attributes.collect { |a| "'#{a}'"}.join(", ")});"
54
+ attribute_initializers << "this.unserializableAttributes([#{unserializable_attributes.collect { |a| "'#{a}'"}.join(", ")}]);"
55
55
 
56
56
  @model_attributes.in_groups_of(5, false) do |group|
57
57
  serializable_attribute_strings << ' ' + group.collect { |attribute| "'#{attribute}'" }.join(', ') + ",\n"
@@ -59,7 +59,7 @@ class Kea::ModelGenerator < Rails::Generators::NamedBase
59
59
 
60
60
  serializable_attribute_strings.gsub!(/,\n\z/, "\n")
61
61
 
62
- attribute_initializers << "this.serializable_attributes(\n#{serializable_attribute_strings} );"
62
+ attribute_initializers << "this.serializableAttributes([\n#{serializable_attribute_strings} ]);"
63
63
 
64
64
  @model_associations.each do |assoc|
65
65
  attribute_initializers << case assoc.macro
@@ -1,3 +1,3 @@
1
1
  module Kea
2
- VERSION = "2.0.0-alpha9"
2
+ VERSION = "2.0.0-alpha10"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kea-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre.alpha9
4
+ version: 2.0.0.pre.alpha10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan-Christian Foeh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-23 00:00:00.000000000 Z
11
+ date: 2015-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -98,7 +98,6 @@ files:
98
98
  - vendor/assets/components/Keypress/README.md
99
99
  - vendor/assets/components/Keypress/bower.json
100
100
  - vendor/assets/components/Keypress/keypress-2.1.0.min.js
101
- - vendor/assets/components/Keypress/keypress.coffee
102
101
  - vendor/assets/components/Keypress/keypress.js
103
102
  - vendor/assets/components/Keypress/package.json
104
103
  - vendor/assets/components/attachejs/attache-jquery.js
@@ -1,921 +0,0 @@
1
- ###
2
- Copyright 2014 David Mauro
3
-
4
- Licensed under the Apache License, Version 2.0 (the "License");
5
- you may not use this file except in compliance with the License.
6
- You may obtain a copy of the License at
7
-
8
- http://www.apache.org/licenses/LICENSE-2.0
9
-
10
- Unless required by applicable law or agreed to in writing, software
11
- distributed under the License is distributed on an "AS IS" BASIS,
12
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- See the License for the specific language governing permissions and
14
- limitations under the License.
15
-
16
- Keypress is a robust keyboard input capturing Javascript utility
17
- focused on input for games.
18
-
19
- version 2.1.0
20
- ###
21
-
22
- ###
23
- Combo options available and their defaults:
24
- keys : [] - An array of the keys pressed together to activate combo.
25
- count : 0 - The number of times a counting combo has been pressed. Reset on release.
26
- is_unordered : false - Unless this is set to true, the keys can be pressed down in any order.
27
- is_counting : false - Makes this a counting combo (see documentation).
28
- is_exclusive : false - This combo will replace other exclusive combos when true.
29
- is_solitary : false - This combo will only fire if ONLY it's keys are pressed down.
30
- is_sequence : false - Rather than a key combo, this is an ordered key sequence.
31
- prevent_default : false - Prevent default behavior for all component key keypresses.
32
- prevent_repeat : false - Prevent the combo from repeating when keydown is held.
33
- on_keydown : null - A function that is called when the combo is pressed.
34
- on_keyup : null - A function that is called when the combo is released.
35
- on_release : null - A function that is called when all keys in the combo are released.
36
- this : undefined - Defines the scope for your callback functions.
37
- ###
38
-
39
- ###########
40
- # Constants
41
- ###########
42
-
43
- _factory_defaults =
44
- is_unordered : false
45
- is_counting : false
46
- is_exclusive : false
47
- is_solitary : false
48
- prevent_default : false
49
- prevent_repeat : false
50
-
51
- _modifier_keys = ["meta", "alt", "option", "ctrl", "shift", "cmd"]
52
-
53
- _metakey = "ctrl"
54
-
55
- ###########################
56
- # Public object and Classes
57
- ###########################
58
-
59
- keypress = {}
60
-
61
- keypress.debug = false
62
-
63
- class Combo
64
- constructor: (dictionary) ->
65
- # Copy over any non-false values
66
- for own property, value of dictionary
67
- @[property] = value if value != false
68
-
69
- # Standard Defaults
70
- @keys = @keys or []
71
- @count = @count or 0
72
-
73
- allows_key_repeat: ->
74
- # Combos with keydown functions should be able to rapid fire
75
- # when holding down the key for an extended period
76
- return not @prevent_repeat and typeof @on_keydown is "function"
77
-
78
- reset: ->
79
- @count = 0
80
- @keyup_fired = null
81
-
82
- class keypress.Listener
83
- constructor:(element, defaults) ->
84
- # Public properties
85
- @should_suppress_event_defaults = false
86
- @should_force_event_defaults = false
87
- @sequence_delay = 800
88
-
89
- # Private properties
90
- @_registered_combos = []
91
- @_keys_down = []
92
- @_active_combos = []
93
- @_sequence = []
94
- @_sequence_timer = null
95
- @_prevent_capture = false
96
- @_defaults = defaults or {}
97
- for own property, value of _factory_defaults
98
- @_defaults[property] = @_defaults[property] or value
99
-
100
- # Attach handlers to element
101
- @element = element or document.body
102
-
103
- attach_handler = (target, event, handler) ->
104
- if target.addEventListener
105
- target.addEventListener event, handler
106
- else if target.attachEvent
107
- target.attachEvent "on#{event}", handler
108
-
109
- return handler
110
-
111
- @keydown_event = attach_handler @element, "keydown", (e) =>
112
- e = e or window.event
113
- @_receive_input e, true
114
- @_bug_catcher e
115
-
116
- @keyup_event = attach_handler @element, "keyup", (e) =>
117
- e = e or window.event
118
- @_receive_input e, false
119
-
120
- @blur_event = attach_handler window, "blur", =>
121
- # Assume all keys are released when we can't catch key events
122
- # This prevents alt+tab conflicts
123
- for key in @_keys_down
124
- @_key_up key, {}
125
- @_keys_down = []
126
-
127
- destroy: () ->
128
- remove_handler = (target, event, handler) ->
129
- if target.removeEventListener?
130
- target.removeEventListener event, handler
131
- else if target.removeEvent?
132
- target.removeEvent "on#{event}", handler
133
-
134
- remove_handler @element, "keydown", @keydown_event
135
- remove_handler @element, "keyup", @keyup_event
136
- remove_handler window, "blur", @blur_event
137
-
138
- # Helper Methods
139
-
140
- _bug_catcher: (e) ->
141
- # This seems to be Mac specific weirdness, so we'll target "cmd" as metaKey
142
- # Force a keyup for non-modifier keys when command is held because they don't fire
143
- if _metakey is "cmd" and "cmd" in @_keys_down and _convert_key_to_readable(e.keyCode) not in ["cmd", "shift", "alt", "caps", "tab"]
144
- @_receive_input e, false
145
- # Note: we're currently ignoring the fact that this doesn't catch the bug that a keyup
146
- # will not fire if you keydown a combo, then press and hold cmd, then keyup the combo.
147
- # Perhaps we should fire keyup on all active combos when we press cmd?
148
-
149
- _cmd_bug_check: (combo_keys) ->
150
- # We don't want to allow combos to activate if the cmd key
151
- # is pressed, but cmd isn't in them. This is so they don't
152
- # accidentally rapid fire due to our hack-around for the cmd
153
- # key bug and having to fake keyups.
154
- if _metakey is "cmd" and "cmd" in @_keys_down and "cmd" not in combo_keys
155
- return false
156
- return true
157
-
158
- _prevent_default: (e, should_prevent) ->
159
- # If we've pressed a combo, or if we are working towards
160
- # one, we should prevent the default keydown event.
161
- if (should_prevent or @should_suppress_event_defaults) and not @should_force_event_defaults
162
- if e.preventDefault then e.preventDefault() else e.returnValue = false
163
- e.stopPropagation() if e.stopPropagation
164
-
165
- # Tracking Combos
166
-
167
- _get_active_combos: (key) ->
168
- # Based on the keys_down and the key just pressed or released
169
- # (which should not be in keys_down), we determine if any
170
- # combo in registered_combos could be considered active.
171
- # This will return an array of active combos
172
-
173
- active_combos = []
174
-
175
- # First check that every key in keys_down maps to a combo
176
- keys_down = _filter_array @_keys_down, (down_key) ->
177
- down_key isnt key
178
- keys_down.push key
179
-
180
- # Get perfect matches
181
- @_match_combo_arrays keys_down, (match) =>
182
- active_combos.push(match) if @_cmd_bug_check match.keys
183
-
184
- # Get fuzzy matches
185
- @_fuzzy_match_combo_arrays keys_down, (match) =>
186
- return if match in active_combos
187
- active_combos.push(match) unless match.is_solitary or not @_cmd_bug_check match.keys
188
-
189
- return active_combos
190
-
191
- _get_potential_combos: (key) ->
192
- # Check if we are working towards pressing a combo.
193
- # Used for preventing default on keys that might match
194
- # to a combo in the future.
195
- potentials = []
196
- for combo in @_registered_combos
197
- continue if combo.is_sequence
198
- potentials.push(combo) if key in combo.keys and @_cmd_bug_check combo.keys
199
- return potentials
200
-
201
- _add_to_active_combos: (combo) ->
202
- should_replace = false
203
- should_prepend = true
204
- already_replaced = false
205
- # An active combo is any combo which the user has already entered.
206
- # We use this to track when a user has released the last key of a
207
- # combo for on_release, and to keep combos from 'overlapping'.
208
- if combo in @_active_combos
209
- return true
210
- else if @_active_combos.length
211
- # We have to check if we're replacing another active combo
212
- # So compare the combo.keys to all active combos' keys.
213
- for i in [0...@_active_combos.length]
214
- active_combo = @_active_combos[i]
215
- continue unless active_combo and active_combo.is_exclusive and combo.is_exclusive
216
- active_keys = active_combo.keys
217
- unless should_replace
218
- for active_key in active_keys
219
- should_replace = true
220
- unless active_key in combo.keys
221
- should_replace = false
222
- break
223
-
224
- if should_prepend and not should_replace
225
- for combo_key in combo.keys
226
- should_prepend = false
227
- unless combo_key in active_keys
228
- should_prepend = true
229
- break
230
-
231
- if should_replace
232
- if already_replaced
233
- active_combo = @_active_combos.splice(i, 1)[0]
234
- active_combo.reset() if active_combo?
235
- else
236
- active_combo = @_active_combos.splice(i, 1, combo)[0]
237
- active_combo.reset() if active_combo?
238
- already_replaced = true
239
- should_prepend = false
240
- if should_prepend
241
- @_active_combos.unshift combo
242
-
243
- return should_replace or should_prepend
244
-
245
- _remove_from_active_combos: (combo) ->
246
- for i in [0...@_active_combos.length]
247
- active_combo = @_active_combos[i]
248
- if active_combo is combo
249
- combo = @_active_combos.splice(i, 1)[0]
250
- combo.reset()
251
- break
252
- return
253
-
254
- # Sequence Methods
255
-
256
- _get_possible_sequences: ->
257
- # Determine what if any sequences we're working towards.
258
- # We will consider any which any part of the end of the sequence
259
- # matches and return all of them.
260
- matches = []
261
- for combo in @_registered_combos
262
- for j in [1..@_sequence.length]
263
- sequence = @_sequence.slice -j
264
- continue unless combo.is_sequence
265
- unless "shift" in combo.keys
266
- sequence = _filter_array sequence, (key) ->
267
- return key isnt "shift"
268
- continue unless sequence.length
269
- for i in [0...sequence.length]
270
- if combo.keys[i] is sequence[i]
271
- match = true
272
- else
273
- match = false
274
- break
275
- matches.push(combo) if match
276
- return matches
277
-
278
- _add_key_to_sequence: (key, e) ->
279
- @_sequence.push key
280
- # Now check if they're working towards a sequence
281
- sequence_combos = @_get_possible_sequences()
282
- if sequence_combos.length
283
- for combo in sequence_combos
284
- @_prevent_default e, combo.prevent_default
285
- # If we're working towards one, give them more time to keep going
286
- clearTimeout(@_sequence_timer) if @_sequence_timer
287
- if @sequence_delay > -1
288
- @_sequence_timer = setTimeout ->
289
- @_sequence = []
290
- , @sequence_delay
291
- else
292
- # If we're not working towards something, just clear it out
293
- @_sequence = []
294
- return
295
-
296
- _get_sequence: (key) ->
297
- # Compare _sequence to all combos
298
- for combo in @_registered_combos
299
- continue unless combo.is_sequence
300
- for j in [1..@_sequence.length]
301
- # As we are traversing backwards through the sequence keys,
302
- # Take out any shift keys, unless shift is in the combo.
303
- sequence = (_filter_array @_sequence, (seq_key) ->
304
- return true if "shift" in combo.keys
305
- return seq_key isnt "shift"
306
- ).slice -j
307
- continue unless combo.keys.length is sequence.length
308
- for i in [0...sequence.length]
309
- seq_key = sequence[i]
310
- # Special case for shift. Ignore shift keys, unless the sequence explicitly uses them
311
- continue if seq_key is "shift" unless "shift" in combo.keys
312
- # Don't select this combo if we're pressing shift and shift isn't in it
313
- continue if key is "shift" and "shift" not in combo.keys
314
- if combo.keys[i] is seq_key
315
- match = true
316
- else
317
- match = false
318
- break
319
- return combo if match
320
- return false
321
-
322
- # Catching Combos
323
-
324
- _receive_input: (e, is_keydown) ->
325
- # If we're not capturing input, we should
326
- # clear out _keys_down for good measure
327
- if @_prevent_capture
328
- @_keys_down = [] if @_keys_down.length
329
- return
330
- key = _convert_key_to_readable e.keyCode
331
- # Catch tabbing out of a non-capturing state
332
- if !is_keydown and !@_keys_down.length and key in ["alt", _metakey]
333
- return
334
- return unless key
335
- if is_keydown
336
- @_key_down key, e
337
- else
338
- @_key_up key, e
339
-
340
- _fire: (event, combo, key_event, is_autorepeat) ->
341
- # Only fire this event if the function is defined
342
- if typeof combo["on_" + event] is "function"
343
- @_prevent_default key_event, (combo["on_" + event].call(combo.this, key_event, combo.count, is_autorepeat) isnt true)
344
- # We need to mark that keyup has already happened
345
- if event is "release"
346
- combo.count = 0
347
- if event is "keyup"
348
- combo.keyup_fired = true
349
-
350
- _match_combo_arrays: (potential_match, match_handler) ->
351
- # This will return all combos that match
352
- for source_combo in @_registered_combos
353
- if (not source_combo.is_unordered and _compare_arrays_sorted(potential_match, source_combo.keys)) or (source_combo.is_unordered and _compare_arrays(potential_match, source_combo.keys))
354
- match_handler source_combo
355
- return
356
-
357
- _fuzzy_match_combo_arrays: (potential_match, match_handler) ->
358
- # This will return combos that match even if other keys are pressed
359
- for source_combo in @_registered_combos
360
- if (not source_combo.is_unordered and _is_array_in_array_sorted(source_combo.keys, potential_match)) or (source_combo.is_unordered and _is_array_in_array(source_combo.keys, potential_match))
361
- match_handler source_combo
362
- return
363
-
364
- _keys_remain: (combo) ->
365
- for key in combo.keys
366
- if key in @_keys_down
367
- keys_remain = true
368
- break
369
- return keys_remain
370
-
371
- _key_down: (key, e) ->
372
- # Check if we're holding shift
373
- shifted_key = _convert_to_shifted_key key, e
374
- key = shifted_key if shifted_key
375
-
376
- # Add the key to sequences
377
- @_add_key_to_sequence key, e
378
- sequence_combo = @_get_sequence key
379
- @_fire("keydown", sequence_combo, e) if sequence_combo
380
-
381
- # We might have modifier keys down when coming back to
382
- # this window and they might not be in _keys_down, so
383
- # we're doing a check to make sure we put it back in.
384
- # This only works for explicit modifier keys.
385
- for mod, event_mod of _modifier_event_mapping
386
- continue unless e[event_mod]
387
- continue if mod is key or mod in @_keys_down
388
- @_keys_down.push mod
389
- # Alternatively, we might not have modifier keys down
390
- # that we think are, so we should catch those too
391
- for mod, event_mod of _modifier_event_mapping
392
- continue if mod is key
393
- if mod in @_keys_down and not e[event_mod]
394
- # The Windows key will think it is the cmd key, but won't trigger the event mod
395
- continue if mod is "cmd" and _metakey isnt "cmd"
396
- for i in [0...@_keys_down.length]
397
- @_keys_down.splice(i, 1) if @_keys_down[i] is mod
398
-
399
- # Find which combos we have pressed or might be working towards, and prevent default
400
- combos = @_get_active_combos key
401
- potential_combos = @_get_potential_combos key
402
- for combo in combos
403
- @_handle_combo_down combo, potential_combos, key, e
404
- if potential_combos.length
405
- for potential in potential_combos
406
- @_prevent_default e, potential.prevent_default
407
-
408
- if key not in @_keys_down
409
- @_keys_down.push key
410
- return
411
-
412
- _handle_combo_down: (combo, potential_combos, key, e) ->
413
- # Make sure we're not trying to fire for a combo that already fired
414
- return false unless key in combo.keys
415
-
416
- @_prevent_default e, (combo and combo.prevent_default)
417
-
418
- is_autorepeat = false
419
- # If we've already pressed this key, check that we want to fire
420
- # again, otherwise just add it to the keys_down list.
421
- if key in @_keys_down
422
- is_autorepeat = true
423
- return false unless combo.allows_key_repeat()
424
-
425
- # Now we add this combo or replace it in _active_combos
426
- result = @_add_to_active_combos combo, key
427
-
428
- # We reset the keyup_fired property because you should be
429
- # able to fire that again, if you've pressed the key down again
430
- combo.keyup_fired = false
431
-
432
- # Now we fire the keydown event unless there is a larger exclusive potential combo
433
- is_other_exclusive = false
434
- if combo.is_exclusive
435
- for potential_combo in potential_combos
436
- if potential_combo.is_exclusive and potential_combo.keys.length > combo.keys.length
437
- is_other_exclusive = true
438
- break
439
-
440
- unless is_other_exclusive
441
- if combo.is_counting and typeof combo.on_keydown is "function"
442
- combo.count += 1
443
-
444
- # Only fire keydown if we added it
445
- if result
446
- @_fire "keydown", combo, e, is_autorepeat
447
-
448
- _key_up: (key, e) ->
449
- # Check if we're holding shift
450
- unshifted_key = key
451
- shifted_key = _convert_to_shifted_key key, e
452
- key = shifted_key if shifted_key
453
- shifted_key = _keycode_shifted_keys[unshifted_key]
454
- # We have to make sure the key matches to what we had in _keys_down
455
- if e.shiftKey
456
- key = unshifted_key unless shifted_key and shifted_key in @_keys_down
457
- else
458
- key = shifted_key unless unshifted_key and unshifted_key in @_keys_down
459
-
460
- # Check if we have a keyup firing
461
- sequence_combo = @_get_sequence key
462
- @_fire("keyup", sequence_combo, e) if sequence_combo
463
-
464
- # Remove from the list
465
- return false unless key in @_keys_down
466
- for i in [0...@_keys_down.length]
467
- if @_keys_down[i] in [key, shifted_key, unshifted_key]
468
- @_keys_down.splice i, 1
469
- break
470
-
471
- # Store this for later cleanup
472
- active_combos_length = @_active_combos.length
473
-
474
- # When releasing we should only check if we
475
- # match from _active_combos so that we don't
476
- # accidentally fire for a combo that was a
477
- # smaller part of the one we actually wanted.
478
- combos = []
479
- for active_combo in @_active_combos
480
- if key in active_combo.keys
481
- combos.push active_combo
482
- for combo in combos
483
- @_handle_combo_up combo, e, key
484
-
485
- # We also need to check other combos that might still be in active_combos
486
- # and needs to be removed from it.
487
- if active_combos_length > 1
488
- for active_combo in @_active_combos
489
- continue if active_combo is undefined or active_combo in combos
490
- unless @_keys_remain active_combo
491
- @_remove_from_active_combos active_combo
492
- return
493
-
494
- _handle_combo_up: (combo, e, key) ->
495
- @_prevent_default e, (combo and combo.prevent_default)
496
-
497
- # Check if any keys from this combo are still being held.
498
- keys_remaining = @_keys_remain combo
499
-
500
- # Any unactivated combos will fire
501
- if !combo.keyup_fired
502
- # And we should not fire it if it is a solitary combo and something else is pressed
503
- keys_down = @_keys_down.slice()
504
- keys_down.push key
505
- if not combo.is_solitary or _compare_arrays keys_down, combo.keys
506
- @_fire "keyup", combo, e
507
- # Dont' add to the count unless we only have a keyup callback
508
- if combo.is_counting and typeof combo.on_keyup is "function" and typeof combo.on_keydown isnt "function"
509
- combo.count += 1
510
-
511
- # If this was the last key released of the combo, clean up.
512
- unless keys_remaining
513
- @_fire "release", combo, e
514
- @_remove_from_active_combos combo
515
- return
516
-
517
- # Public Registration Methods
518
-
519
- simple_combo: (keys, callback) ->
520
- # Shortcut for simple combos.
521
- @register_combo(
522
- keys : keys
523
- on_keydown : callback
524
- )
525
-
526
- counting_combo: (keys, count_callback) ->
527
- # Shortcut for counting combos
528
- @register_combo(
529
- keys : keys
530
- is_counting : true
531
- is_unordered : false
532
- on_keydown : count_callback
533
- )
534
-
535
- sequence_combo: (keys, callback) ->
536
- @register_combo(
537
- keys : keys
538
- on_keydown : callback
539
- is_sequence : true
540
- )
541
-
542
- register_combo: (combo_dictionary) ->
543
- # Allow a space dilineated string instead of array
544
- if typeof combo_dictionary["keys"] is "string"
545
- combo_dictionary["keys"] = combo_dictionary["keys"].split " "
546
- for own property, value of @_defaults
547
- if combo_dictionary[property] is undefined
548
- combo_dictionary[property] = value
549
- combo = new Combo combo_dictionary
550
-
551
- if _validate_combo combo
552
- @_registered_combos.push combo
553
- return combo
554
-
555
- register_many: (combo_array) ->
556
- # Will return an array of the combos actually registered
557
- @register_combo(combo) for combo in combo_array
558
-
559
- unregister_combo: (keys_or_combo) ->
560
- return false unless keys_or_combo
561
-
562
- unregister_combo = (combo) =>
563
- for i in [0...@_registered_combos.length]
564
- if combo is @_registered_combos[i]
565
- @_registered_combos.splice i, 1
566
- break
567
-
568
- if keys_or_combo instanceof Combo
569
- unregister_combo keys_or_combo
570
- else
571
- if typeof keys_or_combo is "string"
572
- keys_or_combo = keys_or_combo.split " "
573
- for combo in @_registered_combos
574
- continue unless combo?
575
- if (combo.is_unordered and _compare_arrays(keys_or_combo, combo.keys)) or (not combo.is_unordered and _compare_arrays_sorted(keys_or_combo, combo.keys))
576
- unregister_combo combo
577
-
578
- unregister_many: (combo_array) ->
579
- for combo in combo_array
580
- @unregister_combo combo
581
-
582
- # Other public methods
583
-
584
- get_registered_combos: ->
585
- return @_registered_combos
586
-
587
- reset: ->
588
- @_registered_combos = []
589
-
590
- listen: ->
591
- @_prevent_capture = false
592
-
593
- stop_listening: ->
594
- @_prevent_capture = true
595
-
596
- get_meta_key: ->
597
- # Helpful for debugging purposes
598
- return _metakey
599
-
600
- ##################
601
- # Helper Functions
602
- ##################
603
-
604
- _decide_meta_key = ->
605
- # If the useragent reports Mac OS X, assume cmd is metakey
606
- if navigator.userAgent.indexOf("Mac OS X") != -1
607
- _metakey = "cmd"
608
- return
609
-
610
- _change_keycodes_by_browser = ->
611
- if navigator.userAgent.indexOf("Opera") != -1
612
- # Opera does weird stuff with command and control keys, let's fix that.
613
- # Note: Opera cannot override meta + s browser default of save page.
614
- # Note: Opera does some really strange stuff when cmd+alt+shift
615
- # are held and a non-modifier key is pressed.
616
- _keycode_dictionary["17"] = "cmd"
617
- return
618
-
619
- _convert_key_to_readable = (k) ->
620
- return _keycode_dictionary[k]
621
-
622
- _filter_array = (array, callback) ->
623
- if array.filter
624
- return array.filter(callback)
625
- else
626
- # For browsers without Array.prototype.filter like IE<9:
627
- return (element for element in array when callback(element))
628
-
629
- _compare_arrays = (a1, a2) ->
630
- # This will ignore the ordering of the arrays
631
- # and simply check if they have the same contents.
632
- return false unless a1.length is a2.length
633
- for item in a1
634
- continue if item in a2
635
- return false
636
- return true
637
-
638
- _compare_arrays_sorted = (a1, a2) ->
639
- return false unless a1.length is a2.length
640
- for i in [0...a1.length]
641
- return false unless a1[i] is a2[i]
642
- return true
643
-
644
- _is_array_in_array = (a1, a2) ->
645
- # Returns true only if all of the contents of
646
- # a1 are included in a2
647
- for item in a1
648
- return false unless item in a2
649
- return true
650
-
651
- _index_of_in_array = Array.prototype.indexOf or (a, item) ->
652
- for i in [0..a.length]
653
- return i if a[i] is item
654
- return -1
655
-
656
- _is_array_in_array_sorted = (a1, a2) ->
657
- # Return true only if all of the contents of
658
- # a1 are include in a2 and they appear in the
659
- # same order in both.
660
- prev = 0
661
- for item in a1
662
- index = _index_of_in_array.call a2, item
663
- if index >= prev
664
- prev = index
665
- else
666
- return false
667
- return true
668
-
669
- _log_error = () ->
670
- console.log arguments... if keypress.debug
671
-
672
- _key_is_valid = (key) ->
673
- valid = false
674
- for _, valid_key of _keycode_dictionary
675
- if key is valid_key
676
- valid = true
677
- break
678
- unless valid
679
- for _, valid_key of _keycode_shifted_keys
680
- if key is valid_key
681
- valid = true
682
- break
683
- return valid
684
-
685
- _validate_combo = (combo) ->
686
- validated = true
687
-
688
- # Warn for lack of keys
689
- unless combo.keys.length
690
- _log_error "You're trying to bind a combo with no keys:", combo
691
-
692
- # Convert "meta" to either "ctrl" or "cmd"
693
- # Don't explicity use the command key, it breaks
694
- # because it is the windows key in Windows, and
695
- # cannot be hijacked.
696
- for i in [0...combo.keys.length]
697
- key = combo.keys[i]
698
- # Check the name and replace if needed
699
- alt_name = _keycode_alternate_names[key]
700
- key = combo.keys[i] = alt_name if alt_name
701
- if key is "meta"
702
- combo.keys.splice i, 1, _metakey
703
- if key is "cmd"
704
- _log_error "Warning: use the \"meta\" key rather than \"cmd\" for Windows compatibility"
705
-
706
- # Check that all keys in the combo are valid
707
- for key in combo.keys
708
- unless _key_is_valid key
709
- _log_error "Do not recognize the key \"#{key}\""
710
- validated = false
711
-
712
- # We can only allow a single non-modifier key
713
- # in combos that include the command key (this
714
- # includes 'meta') because of the keyup bug.
715
- if "meta" in combo.keys or "cmd" in combo.keys
716
- non_modifier_keys = combo.keys.slice()
717
- for mod_key in _modifier_keys
718
- if (i = _index_of_in_array.call(non_modifier_keys, mod_key)) > -1
719
- non_modifier_keys.splice(i, 1)
720
- if non_modifier_keys.length > 1
721
- _log_error "META and CMD key combos cannot have more than 1 non-modifier keys", combo, non_modifier_keys
722
- validated = false
723
-
724
- # Tell the user if they are trying to use any
725
- # combo properties that don't actually exist,
726
- # but allow the combo
727
- for property, value of combo
728
- if _factory_defaults[property] is "undefined"
729
- _log_error "The property #{property} is not a valid combo property. Your combo has still been registered."
730
-
731
- return validated
732
-
733
- _convert_to_shifted_key = (key, e) ->
734
- return false unless e.shiftKey
735
- k = _keycode_shifted_keys[key]
736
- return k if k?
737
- return false
738
-
739
- ##########################
740
- # Key Mapping Dictionaries
741
- ##########################
742
-
743
- _modifier_event_mapping =
744
- "cmd" : "metaKey"
745
- "ctrl" : "ctrlKey"
746
- "shift" : "shiftKey"
747
- "alt" : "altKey"
748
-
749
- _keycode_alternate_names =
750
- "escape" : "esc"
751
- "control" : "ctrl"
752
- "command" : "cmd"
753
- "break" : "pause"
754
- "windows" : "cmd"
755
- "option" : "alt"
756
- "caps_lock" : "caps"
757
- "apostrophe" : "\'"
758
- "semicolon" : ";"
759
- "tilde" : "~"
760
- "accent" : "`"
761
- "scroll_lock" : "scroll"
762
- "num_lock" : "num"
763
-
764
- _keycode_shifted_keys =
765
- "/" : "?"
766
- "." : ">"
767
- "," : "<"
768
- "\'" : "\""
769
- ";" : ":"
770
- "[" : "{"
771
- "]" : "}"
772
- "\\" : "|"
773
- "`" : "~"
774
- "=" : "+"
775
- "-" : "_"
776
- "1" : "!"
777
- "2" : "@"
778
- "3" : "#"
779
- "4" : "$"
780
- "5" : "%"
781
- "6" : "^"
782
- "7" : "&"
783
- "8" : "*"
784
- "9" : "("
785
- "0" : ")"
786
-
787
- _keycode_dictionary =
788
- 0 : "\\" # Firefox reports this keyCode when shift is held
789
- 8 : "backspace"
790
- 9 : "tab"
791
- 12 : "num"
792
- 13 : "enter"
793
- 16 : "shift"
794
- 17 : "ctrl"
795
- 18 : "alt"
796
- 19 : "pause"
797
- 20 : "caps"
798
- 27 : "esc"
799
- 32 : "space"
800
- 33 : "pageup"
801
- 34 : "pagedown"
802
- 35 : "end"
803
- 36 : "home"
804
- 37 : "left"
805
- 38 : "up"
806
- 39 : "right"
807
- 40 : "down"
808
- 44 : "print"
809
- 45 : "insert"
810
- 46 : "delete"
811
- 48 : "0"
812
- 49 : "1"
813
- 50 : "2"
814
- 51 : "3"
815
- 52 : "4"
816
- 53 : "5"
817
- 54 : "6"
818
- 55 : "7"
819
- 56 : "8"
820
- 57 : "9"
821
- 65 : "a"
822
- 66 : "b"
823
- 67 : "c"
824
- 68 : "d"
825
- 69 : "e"
826
- 70 : "f"
827
- 71 : "g"
828
- 72 : "h"
829
- 73 : "i"
830
- 74 : "j"
831
- 75 : "k"
832
- 76 : "l"
833
- 77 : "m"
834
- 78 : "n"
835
- 79 : "o"
836
- 80 : "p"
837
- 81 : "q"
838
- 82 : "r"
839
- 83 : "s"
840
- 84 : "t"
841
- 85 : "u"
842
- 86 : "v"
843
- 87 : "w"
844
- 88 : "x"
845
- 89 : "y"
846
- 90 : "z"
847
- 91 : "cmd"
848
- 92 : "cmd"
849
- 93 : "cmd"
850
- 96 : "num_0"
851
- 97 : "num_1"
852
- 98 : "num_2"
853
- 99 : "num_3"
854
- 100 : "num_4"
855
- 101 : "num_5"
856
- 102 : "num_6"
857
- 103 : "num_7"
858
- 104 : "num_8"
859
- 105 : "num_9"
860
- 106 : "num_multiply"
861
- 107 : "num_add"
862
- 108 : "num_enter"
863
- 109 : "num_subtract"
864
- 110 : "num_decimal"
865
- 111 : "num_divide"
866
- 112 : "f1"
867
- 113 : "f2"
868
- 114 : "f3"
869
- 115 : "f4"
870
- 116 : "f5"
871
- 117 : "f6"
872
- 118 : "f7"
873
- 119 : "f8"
874
- 120 : "f9"
875
- 121 : "f10"
876
- 122 : "f11"
877
- 123 : "f12"
878
- 124 : "print"
879
- 144 : "num"
880
- 145 : "scroll"
881
- 186 : ";"
882
- 187 : "="
883
- 188 : ","
884
- 189 : "-"
885
- 190 : "."
886
- 191 : "/"
887
- 192 : "`"
888
- 219 : "["
889
- 220 : "\\"
890
- 221 : "]"
891
- 222 : "\'"
892
- 223 : "`"
893
- 224 : "cmd"
894
- 225 : "alt"
895
- # Opera weirdness
896
- 57392 : "ctrl"
897
- 63289 : "num"
898
- # Firefox weirdness
899
- 59 : ";"
900
- 61 : "-"
901
- 173 : "="
902
-
903
- # For testing only:
904
- keypress._keycode_dictionary = _keycode_dictionary
905
- keypress._is_array_in_array_sorted = _is_array_in_array_sorted
906
-
907
- ############
908
- # Initialize
909
- ############
910
-
911
- _decide_meta_key()
912
- _change_keycodes_by_browser()
913
-
914
- # Anonymous Module Definition
915
- if typeof define is "function" and define.amd
916
- define [], ->
917
- return keypress
918
- else if exports?
919
- exports.keypress = keypress
920
- else
921
- window.keypress = keypress