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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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