syn-rails 3.2.3

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.
@@ -0,0 +1,1055 @@
1
+ (function(){
2
+ Syn.key.browsers = {
3
+ webkit : {
4
+ 'prevent':
5
+ {"keyup":[],"keydown":["char","keypress"],"keypress":["char"]},
6
+ 'character':
7
+ {"keydown":[0,"key"],"keypress":["char","char"],"keyup":[0,"key"]},
8
+ 'specialChars':
9
+ {"keydown":[0,"char"],"keyup":[0,"char"]},
10
+ 'navigation':
11
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
12
+ 'special':
13
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
14
+ 'tab':
15
+ {"keydown":[0,"char"],"keyup":[0,"char"]},
16
+ 'pause-break':
17
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
18
+ 'caps':
19
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
20
+ 'escape':
21
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
22
+ 'num-lock':
23
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
24
+ 'scroll-lock':
25
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
26
+ 'print':
27
+ {"keyup":[0,"key"]},
28
+ 'function':
29
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
30
+ '\r':
31
+ {"keydown":[0,"key"],"keypress":["char","key"],"keyup":[0,"key"]}
32
+ },
33
+ gecko : {
34
+ 'prevent':
35
+ {"keyup":[],"keydown":["char"],"keypress":["char"]},
36
+ 'character':
37
+ {"keydown":[0,"key"],"keypress":["char",0],"keyup":[0,"key"]},
38
+ 'specialChars':
39
+ {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]},
40
+ 'navigation':
41
+ {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]},
42
+ 'special':
43
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
44
+ '\t':
45
+ {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]},
46
+ 'pause-break':
47
+ {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]},
48
+ 'caps':
49
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
50
+ 'escape':
51
+ {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]},
52
+ 'num-lock':
53
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
54
+ 'scroll-lock':
55
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
56
+ 'print':
57
+ {"keyup":[0,"key"]},
58
+ 'function':
59
+ {"keydown":[0,"key"],"keyup":[0,"key"]},
60
+ '\r':
61
+ {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]}
62
+ },
63
+ msie : {
64
+ 'prevent':{"keyup":[],"keydown":["char","keypress"],"keypress":["char"]},
65
+ 'character':{"keydown":[null,"key"],"keypress":[null,"char"],"keyup":[null,"key"]},
66
+ 'specialChars':{"keydown":[null,"char"],"keyup":[null,"char"]},
67
+ 'navigation':{"keydown":[null,"key"],"keyup":[null,"key"]},
68
+ 'special':{"keydown":[null,"key"],"keyup":[null,"key"]},
69
+ 'tab':{"keydown":[null,"char"],"keyup":[null,"char"]},
70
+ 'pause-break':{"keydown":[null,"key"],"keyup":[null,"key"]},
71
+ 'caps':{"keydown":[null,"key"],"keyup":[null,"key"]},
72
+ 'escape':{"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]},
73
+ 'num-lock':{"keydown":[null,"key"],"keyup":[null,"key"]},
74
+ 'scroll-lock':{"keydown":[null,"key"],"keyup":[null,"key"]},
75
+ 'print':{"keyup":[null,"key"]},
76
+ 'function':{"keydown":[null,"key"],"keyup":[null,"key"]},
77
+ '\r':{"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]}
78
+ },
79
+ opera : {
80
+ 'prevent':
81
+ {"keyup":[],"keydown":[],"keypress":["char"]},
82
+ 'character':
83
+ {"keydown":[null,"key"],"keypress":[null,"char"],"keyup":[null,"key"]},
84
+ 'specialChars':
85
+ {"keydown":[null,"char"],"keypress":[null,"char"],"keyup":[null,"char"]},
86
+ 'navigation':
87
+ {"keydown":[null,"key"],"keypress":[null,"key"]},
88
+ 'special':
89
+ {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]},
90
+ 'tab':
91
+ {"keydown":[null,"char"],"keypress":[null,"char"],"keyup":[null,"char"]},
92
+ 'pause-break':
93
+ {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]},
94
+ 'caps':
95
+ {"keydown":[null,"key"],"keyup":[null,"key"]},
96
+ 'escape':
97
+ {"keydown":[null,"key"],"keypress":[null,"key"]},
98
+ 'num-lock':
99
+ {"keyup":[null,"key"],"keydown":[null,"key"],"keypress":[null,"key"]},
100
+ 'scroll-lock':
101
+ {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]},
102
+ 'print':
103
+ {},
104
+ 'function':
105
+ {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]},
106
+ '\r':
107
+ {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]}
108
+ }
109
+ };
110
+
111
+ Syn.mouse.browsers = {
112
+ webkit : {"right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3},"contextmenu":{"button":2,"which":3}},
113
+ "left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}}},
114
+ opera: {"right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3}},
115
+ "left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}}},
116
+ msie: { "right":{"mousedown":{"button":2},"mouseup":{"button":2},"contextmenu":{"button":0}},
117
+ "left":{"mousedown":{"button":1},"mouseup":{"button":1},"click":{"button":0}}},
118
+ chrome : {"right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3},"contextmenu":{"button":2,"which":3}},
119
+ "left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}}},
120
+ gecko: {"left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}},
121
+ "right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3},"contextmenu":{"button":2,"which":3}}}
122
+ }
123
+
124
+ //set browser
125
+ Syn.key.browser =
126
+ (function(){
127
+ if(Syn.key.browsers[window.navigator.userAgent]){
128
+ return Syn.key.browsers[window.navigator.userAgent];
129
+ }
130
+ for(var browser in Syn.browser){
131
+ if(Syn.browser[browser] && Syn.key.browsers[browser]){
132
+ return Syn.key.browsers[browser]
133
+ }
134
+ }
135
+ return Syn.key.browsers.gecko;
136
+ })();
137
+
138
+ Syn.mouse.browser =
139
+ (function(){
140
+ if(Syn.mouse.browsers[window.navigator.userAgent]){
141
+ return Syn.mouse.browsers[window.navigator.userAgent];
142
+ }
143
+ for(var browser in Syn.browser){
144
+ if(Syn.browser[browser] && Syn.mouse.browsers[browser]){
145
+ return Syn.mouse.browsers[browser]
146
+ }
147
+ }
148
+ return Syn.mouse.browsers.gecko;
149
+ })();
150
+ })(true);
151
+ (function(){
152
+ var h = Syn.helpers,
153
+ S = Syn,
154
+
155
+ // gets the selection of an input or textarea
156
+ getSelection = function( el ) {
157
+ // use selectionStart if we can
158
+ if ( el.selectionStart !== undefined ) {
159
+ // this is for opera, so we don't have to focus to type how we think we would
160
+ if ( document.activeElement && document.activeElement != el && el.selectionStart == el.selectionEnd && el.selectionStart == 0 ) {
161
+ return {
162
+ start: el.value.length,
163
+ end: el.value.length
164
+ };
165
+ }
166
+ return {
167
+ start: el.selectionStart,
168
+ end: el.selectionEnd
169
+ }
170
+ } else {
171
+ //check if we aren't focused
172
+ try {
173
+ //try 2 different methods that work differently (IE breaks depending on type)
174
+ if ( el.nodeName.toLowerCase() == 'input' ) {
175
+ var real = h.getWindow(el).document.selection.createRange(),
176
+ r = el.createTextRange();
177
+ r.setEndPoint("EndToStart", real);
178
+
179
+ var start = r.text.length
180
+ return {
181
+ start: start,
182
+ end: start + real.text.length
183
+ }
184
+ }
185
+ else {
186
+ var real = h.getWindow(el).document.selection.createRange(),
187
+ r = real.duplicate(),
188
+ r2 = real.duplicate(),
189
+ r3 = real.duplicate();
190
+ r2.collapse();
191
+ r3.collapse(false);
192
+ r2.moveStart('character', -1)
193
+ r3.moveStart('character', -1)
194
+ //select all of our element
195
+ r.moveToElementText(el)
196
+ //now move our endpoint to the end of our real range
197
+ r.setEndPoint('EndToEnd', real);
198
+ var start = r.text.length - real.text.length,
199
+ end = r.text.length;
200
+ if ( start != 0 && r2.text == "" ) {
201
+ start += 2;
202
+ }
203
+ if ( end != 0 && r3.text == "" ) {
204
+ end += 2;
205
+ }
206
+ //if we aren't at the start, but previous is empty, we are at start of newline
207
+ return {
208
+ start: start,
209
+ end: end
210
+ }
211
+ }
212
+ } catch (e) {
213
+ return {
214
+ start: el.value.length,
215
+ end: el.value.length
216
+ };
217
+ }
218
+ }
219
+ },
220
+ // gets all focusable elements
221
+ getFocusable = function( el ) {
222
+ var document = h.getWindow(el).document,
223
+ res = [];
224
+
225
+ var els = document.getElementsByTagName('*'),
226
+ len = els.length;
227
+
228
+ for ( var i = 0; i < len; i++ ) {
229
+ Syn.isFocusable(els[i]) && els[i] != document.documentElement && res.push(els[i])
230
+ }
231
+ return res;
232
+
233
+
234
+ };
235
+
236
+ /**
237
+ * @add Syn static
238
+ */
239
+ h.extend(Syn, {
240
+ /**
241
+ * @attribute
242
+ * A list of the keys and their keycodes codes you can type.
243
+ * You can add type keys with
244
+ * @codestart
245
+ * Syn('key','delete','title');
246
+ *
247
+ * //or
248
+ *
249
+ * Syn('type','One Two Three[left][left][delete]','title')
250
+ * @codeend
251
+ *
252
+ * The following are a list of keys you can type:
253
+ * @codestart text
254
+ * \b - backspace
255
+ * \t - tab
256
+ * \r - enter
257
+ * ' ' - space
258
+ * a-Z 0-9 - normal characters
259
+ * /!@#$*,.? - All other typeable characters
260
+ * page-up - scrolls up
261
+ * page-down - scrolls down
262
+ * end - scrolls to bottom
263
+ * home - scrolls to top
264
+ * insert - changes how keys are entered
265
+ * delete - deletes the next character
266
+ * left - moves cursor left
267
+ * right - moves cursor right
268
+ * up - moves the cursor up
269
+ * down - moves the cursor down
270
+ * f1-12 - function buttons
271
+ * shift, ctrl, alt - special keys
272
+ * pause-break - the pause button
273
+ * scroll-lock - locks scrolling
274
+ * caps - makes caps
275
+ * escape - escape button
276
+ * num-lock - allows numbers on keypad
277
+ * print - screen capture
278
+ * @codeend
279
+ */
280
+ keycodes: {
281
+ //backspace
282
+ '\b': '8',
283
+
284
+ //tab
285
+ '\t': '9',
286
+
287
+ //enter
288
+ '\r': '13',
289
+
290
+ //special
291
+ 'shift': '16',
292
+ 'ctrl': '17',
293
+ 'alt': '18',
294
+
295
+ //weird
296
+ 'pause-break': '19',
297
+ 'caps': '20',
298
+ 'escape': '27',
299
+ 'num-lock': '144',
300
+ 'scroll-lock': '145',
301
+ 'print': '44',
302
+
303
+ //navigation
304
+ 'page-up': '33',
305
+ 'page-down': '34',
306
+ 'end': '35',
307
+ 'home': '36',
308
+ 'left': '37',
309
+ 'up': '38',
310
+ 'right': '39',
311
+ 'down': '40',
312
+ 'insert': '45',
313
+ 'delete': '46',
314
+
315
+ //normal characters
316
+ ' ': '32',
317
+ '0': '48',
318
+ '1': '49',
319
+ '2': '50',
320
+ '3': '51',
321
+ '4': '52',
322
+ '5': '53',
323
+ '6': '54',
324
+ '7': '55',
325
+ '8': '56',
326
+ '9': '57',
327
+ 'a': '65',
328
+ 'b': '66',
329
+ 'c': '67',
330
+ 'd': '68',
331
+ 'e': '69',
332
+ 'f': '70',
333
+ 'g': '71',
334
+ 'h': '72',
335
+ 'i': '73',
336
+ 'j': '74',
337
+ 'k': '75',
338
+ 'l': '76',
339
+ 'm': '77',
340
+ 'n': '78',
341
+ 'o': '79',
342
+ 'p': '80',
343
+ 'q': '81',
344
+ 'r': '82',
345
+ 's': '83',
346
+ 't': '84',
347
+ 'u': '85',
348
+ 'v': '86',
349
+ 'w': '87',
350
+ 'x': '88',
351
+ 'y': '89',
352
+ 'z': '90',
353
+ //normal-characters, numpad
354
+ 'num0': '96',
355
+ 'num1': '97',
356
+ 'num2': '98',
357
+ 'num3': '99',
358
+ 'num4': '100',
359
+ 'num5': '101',
360
+ 'num6': '102',
361
+ 'num7': '103',
362
+ 'num8': '104',
363
+ 'num9': '105',
364
+ '*': '106',
365
+ '+': '107',
366
+ '-': '109',
367
+ '.': '110',
368
+ //normal-characters, others
369
+ '/': '111',
370
+ ';': '186',
371
+ '=': '187',
372
+ ',': '188',
373
+ '-': '189',
374
+ '.': '190',
375
+ '/': '191',
376
+ '`': '192',
377
+ '[': '219',
378
+ '\\': '220',
379
+ ']': '221',
380
+ "'": '222',
381
+
382
+ //ignore these, you shouldn't use them
383
+ 'left window key': '91',
384
+ 'right window key': '92',
385
+ 'select key': '93',
386
+
387
+
388
+ 'f1': '112',
389
+ 'f2': '113',
390
+ 'f3': '114',
391
+ 'f4': '115',
392
+ 'f5': '116',
393
+ 'f6': '117',
394
+ 'f7': '118',
395
+ 'f8': '119',
396
+ 'f9': '120',
397
+ 'f10': '121',
398
+ 'f11': '122',
399
+ 'f12': '123'
400
+ },
401
+
402
+ // what we can type in
403
+ typeable: /input|textarea/i,
404
+
405
+ // selects text on an element
406
+ selectText: function( el, start, end ) {
407
+ if ( el.setSelectionRange ) {
408
+ if (!end ) {
409
+ el.focus();
410
+ el.setSelectionRange(start, start);
411
+ } else {
412
+ el.selectionStart = start;
413
+ el.selectionEnd = end;
414
+ }
415
+ } else if ( el.createTextRange ) {
416
+ //el.focus();
417
+ var r = el.createTextRange();
418
+ r.moveStart('character', start);
419
+ end = end || start;
420
+ r.moveEnd('character', end - el.value.length);
421
+
422
+ r.select();
423
+ }
424
+ },
425
+ getText: function( el ) {
426
+ //first check if the el has anything selected ..
427
+ if ( Syn.typeable.test(el.nodeName) ) {
428
+ var sel = getSelection(el);
429
+ return el.value.substring(sel.start, sel.end)
430
+ }
431
+ //otherwise get from page
432
+ var win = Syn.helpers.getWindow(el);
433
+ if ( win.getSelection ) {
434
+ return win.getSelection().toString();
435
+ }
436
+ else if ( win.document.getSelection ) {
437
+ return win.document.getSelection().toString()
438
+ }
439
+ else {
440
+ return win.document.selection.createRange().text;
441
+ }
442
+ },
443
+ getSelection: getSelection
444
+ });
445
+
446
+ h.extend(Syn.key, {
447
+ // retrieves a description of what events for this character should look like
448
+ data: function( key ) {
449
+ //check if it is described directly
450
+ if ( S.key.browser[key] ) {
451
+ return S.key.browser[key];
452
+ }
453
+ for ( var kind in S.key.kinds ) {
454
+ if ( h.inArray(key, S.key.kinds[kind]) > -1 ) {
455
+ return S.key.browser[kind]
456
+ }
457
+ }
458
+ return S.key.browser.character
459
+ },
460
+
461
+ //returns the special key if special
462
+ isSpecial: function( keyCode ) {
463
+ var specials = S.key.kinds.special;
464
+ for ( var i = 0; i < specials.length; i++ ) {
465
+ if ( Syn.keycodes[specials[i]] == keyCode ) {
466
+ return specials[i];
467
+ }
468
+ }
469
+ },
470
+ /**
471
+ * @hide
472
+ * gets the options for a key and event type ...
473
+ * @param {Object} key
474
+ * @param {Object} event
475
+ */
476
+ options: function( key, event ) {
477
+ var keyData = Syn.key.data(key);
478
+
479
+ if (!keyData[event] ) {
480
+ //we shouldn't be creating this event
481
+ return null;
482
+ }
483
+
484
+ var charCode = keyData[event][0],
485
+ keyCode = keyData[event][1],
486
+ result = {};
487
+
488
+ if ( keyCode == 'key' ) {
489
+ result.keyCode = Syn.keycodes[key]
490
+ } else if ( keyCode == 'char' ) {
491
+ result.keyCode = key.charCodeAt(0)
492
+ } else {
493
+ result.keyCode = keyCode;
494
+ }
495
+
496
+ if ( charCode == 'char' ) {
497
+ result.charCode = key.charCodeAt(0)
498
+ } else if ( charCode !== null ) {
499
+ result.charCode = charCode;
500
+ }
501
+
502
+
503
+ return result
504
+ },
505
+ //types of event keys
506
+ kinds: {
507
+ special: ["shift", 'ctrl', 'alt', 'caps'],
508
+ specialChars: ["\b"],
509
+ navigation: ["page-up", 'page-down', 'end', 'home', 'left', 'up', 'right', 'down', 'insert', 'delete'],
510
+ 'function': ['f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12']
511
+ },
512
+ //returns the default function
513
+ getDefault: function( key ) {
514
+ //check if it is described directly
515
+ if ( Syn.key.defaults[key] ) {
516
+ return Syn.key.defaults[key];
517
+ }
518
+ for ( var kind in Syn.key.kinds ) {
519
+ if ( h.inArray(key, Syn.key.kinds[kind]) > -1 && Syn.key.defaults[kind] ) {
520
+ return Syn.key.defaults[kind];
521
+ }
522
+ }
523
+ return Syn.key.defaults.character
524
+ },
525
+ // default behavior when typing
526
+ defaults: {
527
+ 'character': function( options, scope, key, force, sel ) {
528
+ if (/num\d+/.test(key) ) {
529
+ key = key.match(/\d+/)[0]
530
+ }
531
+
532
+ if ( force || (!S.support.keyCharacters && Syn.typeable.test(this.nodeName)) ) {
533
+ var current = this.value,
534
+ before = current.substr(0, sel.start),
535
+ after = current.substr(sel.end),
536
+ character = key;
537
+
538
+ this.value = before + character + after;
539
+ //handle IE inserting \r\n
540
+ var charLength = character == "\n" && S.support.textareaCarriage ? 2 : character.length;
541
+ Syn.selectText(this, before.length + charLength)
542
+ }
543
+ },
544
+ 'c': function( options, scope, key, force, sel ) {
545
+ if ( Syn.key.ctrlKey ) {
546
+ Syn.key.clipboard = Syn.getText(this)
547
+ } else {
548
+ Syn.key.defaults.character.apply(this, arguments);
549
+ }
550
+ },
551
+ 'v': function( options, scope, key, force, sel ) {
552
+ if ( Syn.key.ctrlKey ) {
553
+ Syn.key.defaults.character.call(this, options, scope, Syn.key.clipboard, true, sel);
554
+ } else {
555
+ Syn.key.defaults.character.apply(this, arguments);
556
+ }
557
+ },
558
+ 'a': function( options, scope, key, force, sel ) {
559
+ if ( Syn.key.ctrlKey ) {
560
+ Syn.selectText(this, 0, this.value.length)
561
+ } else {
562
+ Syn.key.defaults.character.apply(this, arguments);
563
+ }
564
+ },
565
+ 'home': function() {
566
+ Syn.onParents(this, function( el ) {
567
+ if ( el.scrollHeight != el.clientHeight ) {
568
+ el.scrollTop = 0;
569
+ return false;
570
+ }
571
+ })
572
+ },
573
+ 'end': function() {
574
+ Syn.onParents(this, function( el ) {
575
+ if ( el.scrollHeight != el.clientHeight ) {
576
+ el.scrollTop = el.scrollHeight;
577
+ return false;
578
+ }
579
+ })
580
+ },
581
+ 'page-down': function() {
582
+ //find the first parent we can scroll
583
+ Syn.onParents(this, function( el ) {
584
+ if ( el.scrollHeight != el.clientHeight ) {
585
+ var ch = el.clientHeight
586
+ el.scrollTop += ch;
587
+ return false;
588
+ }
589
+ })
590
+ },
591
+ 'page-up': function() {
592
+ Syn.onParents(this, function( el ) {
593
+ if ( el.scrollHeight != el.clientHeight ) {
594
+ var ch = el.clientHeight
595
+ el.scrollTop -= ch;
596
+ return false;
597
+ }
598
+ })
599
+ },
600
+ '\b': function( options, scope, key, force, sel ) {
601
+ //this assumes we are deleting from the end
602
+ if (!S.support.backspaceWorks && Syn.typeable.test(this.nodeName) ) {
603
+ var current = this.value,
604
+ before = current.substr(0, sel.start),
605
+ after = current.substr(sel.end);
606
+
607
+ if ( sel.start == sel.end && sel.start > 0 ) {
608
+ //remove a character
609
+ this.value = before.substring(0, before.length - 1) + after
610
+ Syn.selectText(this, sel.start - 1)
611
+ } else {
612
+ this.value = before + after;
613
+ Syn.selectText(this, sel.start)
614
+ }
615
+
616
+ //set back the selection
617
+ }
618
+ },
619
+ 'delete': function( options, scope, key, force, sel ) {
620
+ if (!S.support.backspaceWorks && Syn.typeable.test(this.nodeName) ) {
621
+ var current = this.value,
622
+ before = current.substr(0, sel.start),
623
+ after = current.substr(sel.end);
624
+ if ( sel.start == sel.end && sel.start <= this.value.length - 1 ) {
625
+ this.value = before + after.substring(1)
626
+ } else {
627
+ this.value = before + after;
628
+
629
+ }
630
+ Syn.selectText(this, sel.start)
631
+ }
632
+ },
633
+ '\r': function( options, scope, key, force, sel ) {
634
+
635
+ var nodeName = this.nodeName.toLowerCase()
636
+ // submit a form
637
+ if (!S.support.keypressSubmits && nodeName == 'input' ) {
638
+ var form = Syn.closest(this, "form");
639
+ if ( form ) {
640
+ Syn.trigger("submit", {}, form);
641
+ }
642
+
643
+ }
644
+ //newline in textarea
645
+ if (!S.support.keyCharacters && nodeName == 'textarea' ) {
646
+ Syn.key.defaults.character.call(this, options, scope, "\n", undefined, sel)
647
+ }
648
+ // 'click' hyperlinks
649
+ if (!S.support.keypressOnAnchorClicks && nodeName == 'a' ) {
650
+ Syn.trigger("click", {}, this);
651
+ }
652
+ },
653
+ //
654
+ // Gets all focusable elements. If the element (this)
655
+ // doesn't have a tabindex, finds the next element after.
656
+ // If the element (this) has a tabindex finds the element
657
+ // with the next higher tabindex OR the element with the same
658
+ // tabindex after it in the document.
659
+ // @return the next element
660
+ //
661
+ '\t': function( options, scope ) {
662
+ // focusable elements
663
+ var focusEls = getFocusable(this),
664
+ // the current element's tabindex
665
+ tabIndex = Syn.tabIndex(this),
666
+ // will be set to our guess for the next element
667
+ current = null,
668
+ // the next index we care about
669
+ currentIndex = 1000000000,
670
+ // set to true once we found 'this' element
671
+ found = false,
672
+ i = 0,
673
+ el,
674
+ //the tabindex of the tabable element we are looking at
675
+ elIndex, firstNotIndexed, prev;
676
+ orders = [];
677
+ for (; i < focusEls.length; i++ ) {
678
+ orders.push([focusEls[i], i]);
679
+ }
680
+ var sort = function( order1, order2 ) {
681
+ var el1 = order1[0],
682
+ el2 = order2[0],
683
+ tab1 = Syn.tabIndex(el1) || 0,
684
+ tab2 = Syn.tabIndex(el2) || 0;
685
+ if ( tab1 == tab2 ) {
686
+ return order1[1] - order2[1]
687
+ } else {
688
+ if ( tab1 == 0 ) {
689
+ return 1;
690
+ } else if ( tab2 == 0 ) {
691
+ return -1;
692
+ } else {
693
+ return tab1 - tab2;
694
+ }
695
+ }
696
+ }
697
+ orders.sort(sort);
698
+ //now find current
699
+ for ( i = 0; i < orders.length; i++ ) {
700
+ el = orders[i][0];
701
+ if ( this == el ) {
702
+ if (!Syn.key.shiftKey ) {
703
+ current = orders[i + 1][0];
704
+ if (!current ) {
705
+ current = orders[0][0]
706
+ }
707
+ } else {
708
+ current = orders[i - 1][0];
709
+ if (!current ) {
710
+ current = orders[focusEls.length - 1][0]
711
+ }
712
+ }
713
+
714
+ }
715
+ }
716
+
717
+ //restart if we didn't find anything
718
+ if (!current ) {
719
+ current = firstNotIndexed;
720
+ }
721
+ current && current.focus();
722
+ return current;
723
+ },
724
+ 'left': function( options, scope, key, force, sel ) {
725
+ if ( Syn.typeable.test(this.nodeName) ) {
726
+ if ( Syn.key.shiftKey ) {
727
+ Syn.selectText(this, sel.start == 0 ? 0 : sel.start - 1, sel.end)
728
+ } else {
729
+ Syn.selectText(this, sel.start == 0 ? 0 : sel.start - 1)
730
+ }
731
+ }
732
+ },
733
+ 'right': function( options, scope, key, force, sel ) {
734
+ if ( Syn.typeable.test(this.nodeName) ) {
735
+ if ( Syn.key.shiftKey ) {
736
+ Syn.selectText(this, sel.start, sel.end + 1 > this.value.length ? this.value.length : sel.end + 1)
737
+ } else {
738
+ Syn.selectText(this, sel.end + 1 > this.value.length ? this.value.length : sel.end + 1)
739
+ }
740
+ }
741
+ },
742
+ 'up': function() {
743
+ if (/select/i.test(this.nodeName) ) {
744
+
745
+ this.selectedIndex = this.selectedIndex ? this.selectedIndex - 1 : 0;
746
+ //set this to change on blur?
747
+ }
748
+ },
749
+ 'down': function() {
750
+ if (/select/i.test(this.nodeName) ) {
751
+ Syn.changeOnBlur(this, "selectedIndex", this.selectedIndex)
752
+ this.selectedIndex = this.selectedIndex + 1;
753
+ //set this to change on blur?
754
+ }
755
+ },
756
+ 'shift': function() {
757
+ return null;
758
+ }
759
+ }
760
+ });
761
+
762
+
763
+ h.extend(Syn.create, {
764
+ keydown: {
765
+ setup: function( type, options, element ) {
766
+ if ( h.inArray(options, Syn.key.kinds.special) != -1 ) {
767
+ Syn.key[options + "Key"] = element;
768
+ }
769
+ }
770
+ },
771
+ keypress: {
772
+ setup: function( type, options, element ) {
773
+ // if this browsers supports writing keys on events
774
+ // but doesn't write them if the element isn't focused
775
+ // focus on the element (ignored if already focused)
776
+ if ( S.support.keyCharacters && !S.support.keysOnNotFocused ) {
777
+ element.focus()
778
+ }
779
+ }
780
+ },
781
+ keyup: {
782
+ setup: function( type, options, element ) {
783
+ if ( h.inArray(options, Syn.key.kinds.special) != -1 ) {
784
+ Syn.key[options + "Key"] = null;
785
+ }
786
+ }
787
+ },
788
+ key: {
789
+ // return the options for a key event
790
+ options: function( type, options, element ) {
791
+ //check if options is character or has character
792
+ options = typeof options != "object" ? {
793
+ character: options
794
+ } : options;
795
+
796
+ //don't change the orignial
797
+ options = h.extend({}, options)
798
+ if ( options.character ) {
799
+ h.extend(options, S.key.options(options.character, type));
800
+ delete options.character;
801
+ }
802
+
803
+ options = h.extend({
804
+ ctrlKey: !! Syn.key.ctrlKey,
805
+ altKey: !! Syn.key.altKey,
806
+ shiftKey: !! Syn.key.shiftKey,
807
+ metaKey: !! Syn.key.metaKey
808
+ }, options)
809
+
810
+ return options;
811
+ },
812
+ // creates a key event
813
+ event: function( type, options, element ) { //Everyone Else
814
+ var doc = h.getWindow(element).document || document;
815
+ if ( doc.createEvent ) {
816
+ var event;
817
+
818
+ try {
819
+
820
+ event = doc.createEvent("KeyEvents");
821
+ event.initKeyEvent(type, true, true, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode);
822
+ }
823
+ catch (e) {
824
+ event = h.createBasicStandardEvent(type, options, doc);
825
+ }
826
+ event.synthetic = true;
827
+ return event;
828
+ }
829
+ else {
830
+ var event;
831
+ try {
832
+ event = h.createEventObject.apply(this, arguments);
833
+ h.extend(event, options)
834
+ }
835
+ catch (e) {}
836
+
837
+ return event;
838
+ }
839
+ }
840
+ }
841
+ });
842
+
843
+ var convert = {
844
+ "enter": "\r",
845
+ "backspace": "\b",
846
+ "tab": "\t",
847
+ "space": " "
848
+ }
849
+
850
+ /**
851
+ * @add Syn prototype
852
+ */
853
+ h.extend(Syn.init.prototype, {
854
+ /**
855
+ * @function key
856
+ * Types a single key. The key should be
857
+ * a string that matches a
858
+ * [Syn.static.keycodes].
859
+ *
860
+ * The following sends a carridge return
861
+ * to the 'name' element.
862
+ * @codestart
863
+ * Syn.key('\r','name')
864
+ * @codeend
865
+ * For each character, a keydown, keypress, and keyup is triggered if
866
+ * appropriate.
867
+ * @param {String} options
868
+ * @param {HTMLElement} [element]
869
+ * @param {Function} [callback]
870
+ * @return {HTMLElement} the element currently focused.
871
+ */
872
+ _key: function( options, element, callback ) {
873
+ //first check if it is a special up
874
+ if (/-up$/.test(options) && h.inArray(options.replace("-up", ""), Syn.key.kinds.special) != -1 ) {
875
+ Syn.trigger('keyup', options.replace("-up", ""), element)
876
+ callback(true, element);
877
+ return;
878
+ }
879
+
880
+
881
+ var caret = Syn.typeable.test(element.nodeName) && getSelection(element),
882
+ key = convert[options] || options,
883
+ // should we run default events
884
+ runDefaults = Syn.trigger('keydown', key, element),
885
+
886
+ // a function that gets the default behavior for a key
887
+ getDefault = Syn.key.getDefault,
888
+
889
+ // how this browser handles preventing default events
890
+ prevent = Syn.key.browser.prevent,
891
+
892
+ // the result of the default event
893
+ defaultResult,
894
+
895
+ // options for keypress
896
+ keypressOptions = Syn.key.options(key, 'keypress')
897
+
898
+
899
+ if ( runDefaults ) {
900
+ //if the browser doesn't create keypresses for this key, run default
901
+ if (!keypressOptions ) {
902
+ defaultResult = getDefault(key).call(element, keypressOptions, h.getWindow(element), key, undefined, caret)
903
+ } else {
904
+ //do keypress
905
+ runDefaults = Syn.trigger('keypress', keypressOptions, element)
906
+ if ( runDefaults ) {
907
+ defaultResult = getDefault(key).call(element, keypressOptions, h.getWindow(element), key, undefined, caret)
908
+ }
909
+ }
910
+ } else {
911
+ //canceled ... possibly don't run keypress
912
+ if ( keypressOptions && h.inArray('keypress', prevent.keydown) == -1 ) {
913
+ Syn.trigger('keypress', keypressOptions, element)
914
+ }
915
+ }
916
+ if ( defaultResult && defaultResult.nodeName ) {
917
+ element = defaultResult
918
+ }
919
+
920
+ if ( defaultResult !== null ) {
921
+ setTimeout(function() {
922
+ Syn.trigger('keyup', Syn.key.options(key, 'keyup'), element)
923
+ callback(runDefaults, element)
924
+ }, 1)
925
+ } else {
926
+ callback(runDefaults, element)
927
+ }
928
+
929
+
930
+ //do mouseup
931
+ return element;
932
+ // is there a keypress? .. if not , run default
933
+ // yes -> did we prevent it?, if not run ...
934
+ },
935
+ /**
936
+ * @function type
937
+ * Types sequence of [Syn.key key actions]. Each
938
+ * character is typed, one at a type.
939
+ * Multi-character keys like 'left' should be
940
+ * enclosed in square brackents.
941
+ *
942
+ * The following types 'JavaScript MVC' then deletes the space.
943
+ * @codestart
944
+ * Syn.type('JavaScript MVC[left][left][left]\b','name')
945
+ * @codeend
946
+ *
947
+ * Type is able to handle (and move with) tabs (\t).
948
+ * The following simulates tabing and entering values in a form and
949
+ * eventually submitting the form.
950
+ * @codestart
951
+ * Syn.type("Justin\tMeyer\t27\tjustinbmeyer@gmail.com\r")
952
+ * @codeend
953
+ * @param {String} options the text to type
954
+ * @param {HTMLElement} [element] an element or an id of an element
955
+ * @param {Function} [callback] a function to callback
956
+ */
957
+ _type: function( options, element, callback ) {
958
+ //break it up into parts ...
959
+ //go through each type and run
960
+ var parts = options.match(/(\[[^\]]+\])|([^\[])/g),
961
+ self = this,
962
+ runNextPart = function( runDefaults, el ) {
963
+ var part = parts.shift();
964
+ if (!part ) {
965
+ callback(runDefaults, el);
966
+ return;
967
+ }
968
+ el = el || element;
969
+ if ( part.length > 1 ) {
970
+ part = part.substr(1, part.length - 2)
971
+ }
972
+ self._key(part, el, runNextPart)
973
+ }
974
+
975
+ runNextPart();
976
+
977
+ }
978
+ });
979
+
980
+
981
+ //do support code
982
+ (function() {
983
+ if (!document.body ) {
984
+ setTimeout(arguments.callee, 1)
985
+ return;
986
+ }
987
+
988
+ var div = document.createElement("div"),
989
+ checkbox, submit, form, input, submitted = false,
990
+ anchor, textarea, inputter;
991
+
992
+ div.innerHTML = "<form id='outer'>" +
993
+ "<input name='checkbox' type='checkbox'/>" +
994
+ "<input name='radio' type='radio' />" +
995
+ "<input type='submit' name='submitter'/>" +
996
+ "<input type='input' name='inputter'/>" +
997
+ "<input name='one'>" +
998
+ "<input name='two'/>" +
999
+ "<a href='#abc'></a>" +
1000
+ "<textarea>1\n2</textarea>" +
1001
+ "</form>";
1002
+
1003
+ document.documentElement.appendChild(div);
1004
+ form = div.firstChild;
1005
+ checkbox = form.childNodes[0];
1006
+ submit = form.childNodes[2];
1007
+ anchor = form.getElementsByTagName("a")[0];
1008
+ textarea = form.getElementsByTagName("textarea")[0];
1009
+ inputter = form.childNodes[3];
1010
+
1011
+ form.onsubmit = function( ev ) {
1012
+ if ( ev.preventDefault ) ev.preventDefault();
1013
+ S.support.keypressSubmits = true;
1014
+ ev.returnValue = false;
1015
+ return false;
1016
+ };
1017
+ // Firefox 4 won't write key events if the element isn't focused
1018
+ inputter.focus();
1019
+ Syn.trigger("keypress", "\r", inputter);
1020
+
1021
+
1022
+ Syn.trigger("keypress", "a", inputter);
1023
+ S.support.keyCharacters = inputter.value == "a";
1024
+
1025
+
1026
+ inputter.value = "a";
1027
+ Syn.trigger("keypress", "\b", inputter);
1028
+ S.support.backspaceWorks = inputter.value == "";
1029
+
1030
+
1031
+
1032
+ inputter.onchange = function() {
1033
+ S.support.focusChanges = true;
1034
+ }
1035
+ inputter.focus();
1036
+ Syn.trigger("keypress", "a", inputter);
1037
+ form.childNodes[5].focus(); // this will throw a change event
1038
+ Syn.trigger("keypress", "b", inputter);
1039
+ S.support.keysOnNotFocused = inputter.value == "ab";
1040
+
1041
+ //test keypress \r on anchor submits
1042
+ S.bind(anchor, "click", function( ev ) {
1043
+ if ( ev.preventDefault ) ev.preventDefault();
1044
+ S.support.keypressOnAnchorClicks = true;
1045
+ ev.returnValue = false;
1046
+ return false;
1047
+ })
1048
+ Syn.trigger("keypress", "\r", anchor);
1049
+
1050
+ S.support.textareaCarriage = textarea.value.length == 4
1051
+ document.documentElement.removeChild(div);
1052
+
1053
+ S.support.ready++;
1054
+ })();
1055
+ })(true);