1 |
|
2 | var syn = require('./synthetic.js');
|
3 | require('./typeable.js');
|
4 | require('./browsers.js');
|
5 | var h = syn.helpers, formElExp = /input|textarea/i, supportsSelection = function (el) {
|
6 | var result;
|
7 | try {
|
8 | result = el.selectionStart !== undefined && el.selectionStart !== null;
|
9 | } catch (e) {
|
10 | result = false;
|
11 | }
|
12 | return result;
|
13 | }, getSelection = function (el) {
|
14 | var real, r, start;
|
15 | if (supportsSelection(el)) {
|
16 | if (document.activeElement && document.activeElement !== el && el.selectionStart === el.selectionEnd && el.selectionStart === 0) {
|
17 | return {
|
18 | start: el.value.length,
|
19 | end: el.value.length
|
20 | };
|
21 | }
|
22 | return {
|
23 | start: el.selectionStart,
|
24 | end: el.selectionEnd
|
25 | };
|
26 | } else {
|
27 | try {
|
28 | if (el.nodeName.toLowerCase() === 'input') {
|
29 | real = h.getWindow(el).document.selection.createRange();
|
30 | r = el.createTextRange();
|
31 | r.setEndPoint('EndToStart', real);
|
32 | start = r.text.length;
|
33 | return {
|
34 | start: start,
|
35 | end: start + real.text.length
|
36 | };
|
37 | } else {
|
38 | real = h.getWindow(el).document.selection.createRange();
|
39 | r = real.duplicate();
|
40 | var r2 = real.duplicate(), r3 = real.duplicate();
|
41 | r2.collapse();
|
42 | r3.collapse(false);
|
43 | r2.moveStart('character', -1);
|
44 | r3.moveStart('character', -1);
|
45 | r.moveToElementText(el);
|
46 | r.setEndPoint('EndToEnd', real);
|
47 | start = r.text.length - real.text.length;
|
48 | var end = r.text.length;
|
49 | if (start !== 0 && r2.text === '') {
|
50 | start += 2;
|
51 | }
|
52 | if (end !== 0 && r3.text === '') {
|
53 | end += 2;
|
54 | }
|
55 | return {
|
56 | start: start,
|
57 | end: end
|
58 | };
|
59 | }
|
60 | } catch (e) {
|
61 | var prop = formElExp.test(el.nodeName) ? 'value' : 'textContent';
|
62 | return {
|
63 | start: el[prop].length,
|
64 | end: el[prop].length
|
65 | };
|
66 | }
|
67 | }
|
68 | }, getFocusable = function (el) {
|
69 | var document = h.getWindow(el).document, res = [];
|
70 | var els = document.getElementsByTagName('*'), len = els.length;
|
71 | for (var i = 0; i < len; i++) {
|
72 | if (syn.isFocusable(els[i]) && els[i] !== document.documentElement) {
|
73 | res.push(els[i]);
|
74 | }
|
75 | }
|
76 | return res;
|
77 | }, textProperty = function () {
|
78 | var el = document.createElement('span');
|
79 | return el.textContent != null ? 'textContent' : 'innerText';
|
80 | }(), getText = function (el) {
|
81 | if (formElExp.test(el.nodeName)) {
|
82 | return el.value;
|
83 | }
|
84 | return el[textProperty];
|
85 | }, setText = function (el, value) {
|
86 | if (formElExp.test(el.nodeName)) {
|
87 | el.value = value;
|
88 | } else {
|
89 | el[textProperty] = value;
|
90 | }
|
91 | };
|
92 | h.extend(syn, {
|
93 | keycodes: {
|
94 | '\b': 8,
|
95 | '\t': 9,
|
96 | '\r': 13,
|
97 | 'shift': 16,
|
98 | 'ctrl': 17,
|
99 | 'alt': 18,
|
100 | 'meta': 91,
|
101 | 'pause-break': 19,
|
102 | 'caps': 20,
|
103 | 'escape': 27,
|
104 | 'num-lock': 144,
|
105 | 'scroll-lock': 145,
|
106 | 'print': 44,
|
107 | 'page-up': 33,
|
108 | 'page-down': 34,
|
109 | 'end': 35,
|
110 | 'home': 36,
|
111 | 'left': 37,
|
112 | 'up': 38,
|
113 | 'right': 39,
|
114 | 'down': 40,
|
115 | 'insert': 45,
|
116 | 'delete': 46,
|
117 | ' ': 32,
|
118 | '0': 48,
|
119 | '1': 49,
|
120 | '2': 50,
|
121 | '3': 51,
|
122 | '4': 52,
|
123 | '5': 53,
|
124 | '6': 54,
|
125 | '7': 55,
|
126 | '8': 56,
|
127 | '9': 57,
|
128 | 'a': 65,
|
129 | 'b': 66,
|
130 | 'c': 67,
|
131 | 'd': 68,
|
132 | 'e': 69,
|
133 | 'f': 70,
|
134 | 'g': 71,
|
135 | 'h': 72,
|
136 | 'i': 73,
|
137 | 'j': 74,
|
138 | 'k': 75,
|
139 | 'l': 76,
|
140 | 'm': 77,
|
141 | 'n': 78,
|
142 | 'o': 79,
|
143 | 'p': 80,
|
144 | 'q': 81,
|
145 | 'r': 82,
|
146 | 's': 83,
|
147 | 't': 84,
|
148 | 'u': 85,
|
149 | 'v': 86,
|
150 | 'w': 87,
|
151 | 'x': 88,
|
152 | 'y': 89,
|
153 | 'z': 90,
|
154 | 'num0': 96,
|
155 | 'num1': 97,
|
156 | 'num2': 98,
|
157 | 'num3': 99,
|
158 | 'num4': 100,
|
159 | 'num5': 101,
|
160 | 'num6': 102,
|
161 | 'num7': 103,
|
162 | 'num8': 104,
|
163 | 'num9': 105,
|
164 | '*': 106,
|
165 | '+': 107,
|
166 | 'subtract': 109,
|
167 | 'decimal': 110,
|
168 | 'divide': 111,
|
169 | ';': 186,
|
170 | '=': 187,
|
171 | ',': 188,
|
172 | 'dash': 189,
|
173 | '-': 189,
|
174 | 'period': 190,
|
175 | '.': 190,
|
176 | 'forward-slash': 191,
|
177 | '/': 191,
|
178 | '`': 192,
|
179 | '[': 219,
|
180 | '\\': 220,
|
181 | ']': 221,
|
182 | '\'': 222,
|
183 | 'left window key': 91,
|
184 | 'right window key': 92,
|
185 | 'select key': 93,
|
186 | 'f1': 112,
|
187 | 'f2': 113,
|
188 | 'f3': 114,
|
189 | 'f4': 115,
|
190 | 'f5': 116,
|
191 | 'f6': 117,
|
192 | 'f7': 118,
|
193 | 'f8': 119,
|
194 | 'f9': 120,
|
195 | 'f10': 121,
|
196 | 'f11': 122,
|
197 | 'f12': 123
|
198 | },
|
199 | selectText: function (el, start, end) {
|
200 | if (supportsSelection(el)) {
|
201 | if (!end) {
|
202 | syn.__tryFocus(el);
|
203 | el.setSelectionRange(start, start);
|
204 | } else {
|
205 | el.selectionStart = start;
|
206 | el.selectionEnd = end;
|
207 | }
|
208 | } else if (el.createTextRange) {
|
209 | var r = el.createTextRange();
|
210 | r.moveStart('character', start);
|
211 | end = end || start;
|
212 | r.moveEnd('character', end - el.value.length);
|
213 | r.select();
|
214 | }
|
215 | },
|
216 | getText: function (el) {
|
217 | if (syn.typeable.test(el)) {
|
218 | var sel = getSelection(el);
|
219 | return el.value.substring(sel.start, sel.end);
|
220 | }
|
221 | var win = syn.helpers.getWindow(el);
|
222 | if (win.getSelection) {
|
223 | return win.getSelection().toString();
|
224 | } else if (win.document.getSelection) {
|
225 | return win.document.getSelection().toString();
|
226 | } else {
|
227 | return win.document.selection.createRange().text;
|
228 | }
|
229 | },
|
230 | getSelection: getSelection
|
231 | });
|
232 | h.extend(syn.key, {
|
233 | data: function (key) {
|
234 | if (syn.key.browser[key]) {
|
235 | return syn.key.browser[key];
|
236 | }
|
237 | for (var kind in syn.key.kinds) {
|
238 | if (h.inArray(key, syn.key.kinds[kind]) > -1) {
|
239 | return syn.key.browser[kind];
|
240 | }
|
241 | }
|
242 | return syn.key.browser.character;
|
243 | },
|
244 | isSpecial: function (keyCode) {
|
245 | var specials = syn.key.kinds.special;
|
246 | for (var i = 0; i < specials.length; i++) {
|
247 | if (syn.keycodes[specials[i]] === keyCode) {
|
248 | return specials[i];
|
249 | }
|
250 | }
|
251 | },
|
252 | options: function (key, event) {
|
253 | var keyData = syn.key.data(key);
|
254 | if (!keyData[event]) {
|
255 | return null;
|
256 | }
|
257 | var charCode = keyData[event][0], keyCode = keyData[event][1], result = {};
|
258 | if (keyCode === 'key') {
|
259 | result.keyCode = syn.keycodes[key];
|
260 | } else if (keyCode === 'char') {
|
261 | result.keyCode = key.charCodeAt(0);
|
262 | } else {
|
263 | result.keyCode = keyCode;
|
264 | }
|
265 | if (charCode === 'char') {
|
266 | result.charCode = key.charCodeAt(0);
|
267 | } else if (charCode !== null) {
|
268 | result.charCode = charCode;
|
269 | }
|
270 | if (result.keyCode) {
|
271 | result.which = result.keyCode;
|
272 | } else {
|
273 | result.which = result.charCode;
|
274 | }
|
275 | return result;
|
276 | },
|
277 | kinds: {
|
278 | special: [
|
279 | 'shift',
|
280 | 'ctrl',
|
281 | 'alt',
|
282 | 'meta',
|
283 | 'caps'
|
284 | ],
|
285 | specialChars: ['\b'],
|
286 | navigation: [
|
287 | 'page-up',
|
288 | 'page-down',
|
289 | 'end',
|
290 | 'home',
|
291 | 'left',
|
292 | 'up',
|
293 | 'right',
|
294 | 'down',
|
295 | 'insert',
|
296 | 'delete'
|
297 | ],
|
298 | 'function': [
|
299 | 'f1',
|
300 | 'f2',
|
301 | 'f3',
|
302 | 'f4',
|
303 | 'f5',
|
304 | 'f6',
|
305 | 'f7',
|
306 | 'f8',
|
307 | 'f9',
|
308 | 'f10',
|
309 | 'f11',
|
310 | 'f12'
|
311 | ]
|
312 | },
|
313 | getDefault: function (key) {
|
314 | if (syn.key.defaults[key]) {
|
315 | return syn.key.defaults[key];
|
316 | }
|
317 | for (var kind in syn.key.kinds) {
|
318 | if (h.inArray(key, syn.key.kinds[kind]) > -1 && syn.key.defaults[kind]) {
|
319 | return syn.key.defaults[kind];
|
320 | }
|
321 | }
|
322 | return syn.key.defaults.character;
|
323 | },
|
324 | defaults: {
|
325 | 'character': function (options, scope, key, force, sel) {
|
326 | if (/num\d+/.test(key)) {
|
327 | key = key.match(/\d+/)[0];
|
328 | }
|
329 | if (force || !syn.support.keyCharacters && syn.typeable.test(this)) {
|
330 | var current = getText(this), before = current.substr(0, sel.start), after = current.substr(sel.end), character = key;
|
331 | setText(this, before + character + after);
|
332 | var charLength = character === '\n' && syn.support.textareaCarriage ? 2 : character.length;
|
333 | syn.selectText(this, before.length + charLength);
|
334 | }
|
335 | },
|
336 | 'c': function (options, scope, key, force, sel) {
|
337 | if (syn.key.ctrlKey) {
|
338 | syn.key.clipboard = syn.getText(this);
|
339 | } else {
|
340 | syn.key.defaults.character.apply(this, arguments);
|
341 | }
|
342 | },
|
343 | 'v': function (options, scope, key, force, sel) {
|
344 | if (syn.key.ctrlKey) {
|
345 | syn.key.defaults.character.call(this, options, scope, syn.key.clipboard, true, sel);
|
346 | } else {
|
347 | syn.key.defaults.character.apply(this, arguments);
|
348 | }
|
349 | },
|
350 | 'a': function (options, scope, key, force, sel) {
|
351 | if (syn.key.ctrlKey) {
|
352 | syn.selectText(this, 0, getText(this).length);
|
353 | } else {
|
354 | syn.key.defaults.character.apply(this, arguments);
|
355 | }
|
356 | },
|
357 | 'home': function () {
|
358 | syn.onParents(this, function (el) {
|
359 | if (el.scrollHeight !== el.clientHeight) {
|
360 | el.scrollTop = 0;
|
361 | return false;
|
362 | }
|
363 | });
|
364 | },
|
365 | 'end': function () {
|
366 | syn.onParents(this, function (el) {
|
367 | if (el.scrollHeight !== el.clientHeight) {
|
368 | el.scrollTop = el.scrollHeight;
|
369 | return false;
|
370 | }
|
371 | });
|
372 | },
|
373 | 'page-down': function () {
|
374 | syn.onParents(this, function (el) {
|
375 | if (el.scrollHeight !== el.clientHeight) {
|
376 | var ch = el.clientHeight;
|
377 | el.scrollTop += ch;
|
378 | return false;
|
379 | }
|
380 | });
|
381 | },
|
382 | 'page-up': function () {
|
383 | syn.onParents(this, function (el) {
|
384 | if (el.scrollHeight !== el.clientHeight) {
|
385 | var ch = el.clientHeight;
|
386 | el.scrollTop -= ch;
|
387 | return false;
|
388 | }
|
389 | });
|
390 | },
|
391 | '\b': function (options, scope, key, force, sel) {
|
392 | if (!syn.support.backspaceWorks && syn.typeable.test(this)) {
|
393 | var current = getText(this), before = current.substr(0, sel.start), after = current.substr(sel.end);
|
394 | if (sel.start === sel.end && sel.start > 0) {
|
395 | setText(this, before.substring(0, before.length - 1) + after);
|
396 | syn.selectText(this, sel.start - 1);
|
397 | } else {
|
398 | setText(this, before + after);
|
399 | syn.selectText(this, sel.start);
|
400 | }
|
401 | }
|
402 | },
|
403 | 'delete': function (options, scope, key, force, sel) {
|
404 | if (!syn.support.backspaceWorks && syn.typeable.test(this)) {
|
405 | var current = getText(this), before = current.substr(0, sel.start), after = current.substr(sel.end);
|
406 | if (sel.start === sel.end && sel.start <= getText(this).length - 1) {
|
407 | setText(this, before + after.substring(1));
|
408 | } else {
|
409 | setText(this, before + after);
|
410 | }
|
411 | syn.selectText(this, sel.start);
|
412 | }
|
413 | },
|
414 | '\r': function (options, scope, key, force, sel) {
|
415 | var nodeName = this.nodeName.toLowerCase();
|
416 | if (nodeName === 'input') {
|
417 | syn.trigger(this, 'change', {});
|
418 | }
|
419 | if (!syn.support.keypressSubmits && nodeName === 'input') {
|
420 | var form = syn.closest(this, 'form');
|
421 | if (form) {
|
422 | syn.trigger(form, 'submit', {});
|
423 | }
|
424 | }
|
425 | if (!syn.support.keyCharacters && nodeName === 'textarea') {
|
426 | syn.key.defaults.character.call(this, options, scope, '\n', undefined, sel);
|
427 | }
|
428 | if (!syn.support.keypressOnAnchorClicks && nodeName === 'a') {
|
429 | syn.trigger(this, 'click', {});
|
430 | }
|
431 | },
|
432 | '\t': function (options, scope) {
|
433 | var focusEls = getFocusable(this), current = null, i = 0, el, firstNotIndexed, orders = [];
|
434 | for (; i < focusEls.length; i++) {
|
435 | orders.push([
|
436 | focusEls[i],
|
437 | i
|
438 | ]);
|
439 | }
|
440 | var sort = function (order1, order2) {
|
441 | var el1 = order1[0], el2 = order2[0], tab1 = syn.tabIndex(el1) || 0, tab2 = syn.tabIndex(el2) || 0;
|
442 | if (tab1 === tab2) {
|
443 | return order1[1] - order2[1];
|
444 | } else {
|
445 | if (tab1 === 0) {
|
446 | return 1;
|
447 | } else if (tab2 === 0) {
|
448 | return -1;
|
449 | } else {
|
450 | return tab1 - tab2;
|
451 | }
|
452 | }
|
453 | };
|
454 | orders.sort(sort);
|
455 | var ordersLength = orders.length;
|
456 | for (i = 0; i < ordersLength; i++) {
|
457 | el = orders[i][0];
|
458 | if (this === el) {
|
459 | var nextIndex = i;
|
460 | if (syn.key.shiftKey) {
|
461 | nextIndex--;
|
462 | current = nextIndex >= 0 && orders[nextIndex][0] || orders[ordersLength - 1][0];
|
463 | } else {
|
464 | nextIndex++;
|
465 | current = nextIndex < ordersLength && orders[nextIndex][0] || orders[0][0];
|
466 | }
|
467 | }
|
468 | }
|
469 | if (!current) {
|
470 | current = firstNotIndexed;
|
471 | } else {
|
472 | syn.__tryFocus(current);
|
473 | }
|
474 | return current;
|
475 | },
|
476 | 'left': function (options, scope, key, force, sel) {
|
477 | if (syn.typeable.test(this)) {
|
478 | if (syn.key.shiftKey) {
|
479 | syn.selectText(this, sel.start === 0 ? 0 : sel.start - 1, sel.end);
|
480 | } else {
|
481 | syn.selectText(this, sel.start === 0 ? 0 : sel.start - 1);
|
482 | }
|
483 | }
|
484 | },
|
485 | 'right': function (options, scope, key, force, sel) {
|
486 | if (syn.typeable.test(this)) {
|
487 | if (syn.key.shiftKey) {
|
488 | syn.selectText(this, sel.start, sel.end + 1 > getText(this).length ? getText(this).length : sel.end + 1);
|
489 | } else {
|
490 | syn.selectText(this, sel.end + 1 > getText(this).length ? getText(this).length : sel.end + 1);
|
491 | }
|
492 | }
|
493 | },
|
494 | 'up': function () {
|
495 | if (/select/i.test(this.nodeName)) {
|
496 | this.selectedIndex = this.selectedIndex ? this.selectedIndex - 1 : 0;
|
497 | }
|
498 | },
|
499 | 'down': function () {
|
500 | if (/select/i.test(this.nodeName)) {
|
501 | syn.changeOnBlur(this, 'selectedIndex', this.selectedIndex);
|
502 | this.selectedIndex = this.selectedIndex + 1;
|
503 | }
|
504 | },
|
505 | 'shift': function () {
|
506 | return null;
|
507 | },
|
508 | 'ctrl': function () {
|
509 | return null;
|
510 | },
|
511 | 'alt': function () {
|
512 | return null;
|
513 | },
|
514 | 'meta': function () {
|
515 | return null;
|
516 | }
|
517 | }
|
518 | });
|
519 | h.extend(syn.create, {
|
520 | keydown: {
|
521 | setup: function (type, options, element) {
|
522 | if (h.inArray(options, syn.key.kinds.special) !== -1) {
|
523 | syn.key[options + 'Key'] = element;
|
524 | }
|
525 | }
|
526 | },
|
527 | keypress: {
|
528 | setup: function (type, options, element) {
|
529 | if (syn.support.keyCharacters && !syn.support.keysOnNotFocused) {
|
530 | syn.__tryFocus(element);
|
531 | }
|
532 | }
|
533 | },
|
534 | keyup: {
|
535 | setup: function (type, options, element) {
|
536 | if (h.inArray(options, syn.key.kinds.special) !== -1) {
|
537 | syn.key[options + 'Key'] = null;
|
538 | }
|
539 | }
|
540 | },
|
541 | key: {
|
542 | options: function (type, options, element) {
|
543 | options = typeof options !== 'object' ? { character: options } : options;
|
544 | options = h.extend({}, options);
|
545 | if (options.character) {
|
546 | h.extend(options, syn.key.options(options.character, type));
|
547 | delete options.character;
|
548 | }
|
549 | options = h.extend({
|
550 | ctrlKey: !!syn.key.ctrlKey,
|
551 | altKey: !!syn.key.altKey,
|
552 | shiftKey: !!syn.key.shiftKey,
|
553 | metaKey: !!syn.key.metaKey
|
554 | }, options);
|
555 | return options;
|
556 | },
|
557 | event: function (type, options, element) {
|
558 | var doc = h.getWindow(element).document || document, event;
|
559 | if (doc.createEvent) {
|
560 | try {
|
561 | event = doc.createEvent('KeyEvents');
|
562 | event.initKeyEvent(type, true, true, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode);
|
563 | } catch (e) {
|
564 | event = h.createBasicStandardEvent(type, options, doc);
|
565 | }
|
566 | event.synthetic = true;
|
567 | return event;
|
568 | } else {
|
569 | try {
|
570 | event = h.createEventObject.apply(this, arguments);
|
571 | h.extend(event, options);
|
572 | } catch (e) {
|
573 | }
|
574 | return event;
|
575 | }
|
576 | }
|
577 | }
|
578 | });
|
579 | var convert = {
|
580 | 'enter': '\r',
|
581 | 'backspace': '\b',
|
582 | 'tab': '\t',
|
583 | 'space': ' '
|
584 | };
|
585 | h.extend(syn.init.prototype, {
|
586 | _key: function (element, options, callback) {
|
587 | if (/-up$/.test(options) && h.inArray(options.replace('-up', ''), syn.key.kinds.special) !== -1) {
|
588 | syn.trigger(element, 'keyup', options.replace('-up', ''));
|
589 | return callback(true, element);
|
590 | }
|
591 | var activeElement = h.getWindow(element).document.activeElement, caret = syn.typeable.test(element) && getSelection(element), key = convert[options] || options, runDefaults = syn.trigger(element, 'keydown', key), getDefault = syn.key.getDefault, prevent = syn.key.browser.prevent, defaultResult, keypressOptions = syn.key.options(key, 'keypress');
|
592 | if (runDefaults) {
|
593 | if (!keypressOptions) {
|
594 | defaultResult = getDefault(key).call(element, keypressOptions, h.getWindow(element), key, undefined, caret);
|
595 | } else {
|
596 | if (activeElement !== h.getWindow(element).document.activeElement) {
|
597 | element = h.getWindow(element).document.activeElement;
|
598 | }
|
599 | runDefaults = syn.trigger(element, 'keypress', keypressOptions);
|
600 | if (runDefaults) {
|
601 | defaultResult = getDefault(key).call(element, keypressOptions, h.getWindow(element), key, undefined, caret);
|
602 | }
|
603 | }
|
604 | } else {
|
605 | if (keypressOptions && h.inArray('keypress', prevent.keydown) === -1) {
|
606 | if (activeElement !== h.getWindow(element).document.activeElement) {
|
607 | element = h.getWindow(element).document.activeElement;
|
608 | }
|
609 | syn.trigger(element, 'keypress', keypressOptions);
|
610 | }
|
611 | }
|
612 | if (defaultResult && defaultResult.nodeName) {
|
613 | element = defaultResult;
|
614 | }
|
615 | if (defaultResult !== null) {
|
616 | syn.schedule(function () {
|
617 | if (key === '\r' && element.nodeName.toLowerCase() === 'input') {
|
618 | } else if (syn.support.oninput) {
|
619 | syn.trigger(element, 'input', syn.key.options(key, 'input'));
|
620 | }
|
621 | syn.trigger(element, 'keyup', syn.key.options(key, 'keyup'));
|
622 | callback(runDefaults, element);
|
623 | }, 1);
|
624 | } else {
|
625 | callback(runDefaults, element);
|
626 | }
|
627 | return element;
|
628 | },
|
629 | _type: function (element, options, callback) {
|
630 | var parts = (options + '').match(/(\[[^\]]+\])|([^\[])/g), self = this, runNextPart = function (runDefaults, el) {
|
631 | var part = parts.shift();
|
632 | if (!part) {
|
633 | callback(runDefaults, el);
|
634 | return;
|
635 | }
|
636 | el = el || element;
|
637 | if (part.length > 1) {
|
638 | part = part.substr(1, part.length - 2);
|
639 | }
|
640 | self._key(el, part, runNextPart);
|
641 | };
|
642 | runNextPart();
|
643 | }
|
644 | }); |
\ | No newline at end of file |