forked from iamdanfox/typetype
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjquery.typetype.coffee
117 lines (99 loc) · 3.59 KB
/
jquery.typetype.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
jQuery.fn.extend
backspace: (num, options) ->
settings = jQuery.extend(
callback: () -> # `this` is bound to elem
keypress: () -> # `this` is bound to elem
t:100 # typing interval
e:0.04 # this never gets used, but it takes 2 bytes off!
, options)
return @each ->
elem = @
jQuery(elem).queue ->
attr = if elem.tagName is 'input'.toUpperCase() or
elem.tagName is 'textarea'.toUpperCase()
'value'
else
'innerHTML'
(backsp = (n) ->
if n # > 0
elem[attr] = elem[attr].slice 0, -1
settings.keypress.call elem
setTimeout (-> backsp n-1), Math.random()*settings.t
else
settings.callback.call elem
jQuery(elem).dequeue()
return
)(num)
typetype: (txt, options) ->
settings = jQuery.extend(
callback: () -> # `this` is bound to elem
keypress: () -> # `this` is bound to elem
t:100 # typing interval
e:0.04 # error probability
, options)
interval = (i) -> Math.random() * settings.t * (
if txt[i-1] is txt[i] then 1.6
else if txt[i-1] is '.' then 12
else if txt[i-1] is '!' then 12
else if txt[i-1] is '?' then 12
else if txt[i-1] is '\n' then 12
else if txt[i-1] is ',' then 8
else if txt[i-1] is ';' then 8
else if txt[i-1] is ':' then 8
else if txt[i-1] is ' ' then 3
else 2
)
return @each ->
elem = @
jQuery(elem).queue -> # this function goes into the 'fx' queue.
attr = if elem.tagName is 'input'.toUpperCase() or
elem.tagName is 'textarea'.toUpperCase()
'value'
else
'innerHTML'
append = (str, cont) ->
if str # > 0
elem[attr] += str[0]
settings.keypress.call elem
setTimeout (-> append str.slice(1), cont), settings.t
else
cont()
return
backsp = (num, cont) ->
if num # > 0
elem[attr] = elem[attr].slice 0, -1 # inlined delchar function
settings.keypress.call elem
setTimeout (-> backsp num-1, cont), settings.t
else
cont()
return
(typeTo = (i) ->
if i <= txt.length
afterErr = -> setTimeout (-> typeTo i), interval(i)
r = Math.random() / settings.e
# omit character, recover after 4 more chars
if r<0.3 and txt[i-1] isnt txt[i] and i+4<txt.length
append txt.slice(i,i+4), -> backsp 4, afterErr
# hold shift too long
else if r<0.7 and i>1 and /[A-Z]/.test txt[i-2] and i+4<txt.length
append txt[i-1].toUpperCase()+txt.slice(i,i+4), ->
backsp 5, afterErr
# omit character, recover immediately
else if r<0.5 and txt[i-1] isnt txt[i] and i<txt.length
append txt[i], -> backsp 1, afterErr
# swap two characters
else if r<1.0 and txt[i-1] isnt txt[i] and i<txt.length
append txt[i]+txt[i-1], -> backsp 2, afterErr
# forget to press shift
else if r<0.5 and /[A-Z]/.test txt[i] #uppercase letter coming up
append txt[i].toLowerCase(), -> backsp 1, afterErr
# just insert the correct character!
else
elem[attr] += txt[i-1]
settings.keypress.call elem
setTimeout (-> typeTo i+1), interval(i)
else
settings.callback.call elem
jQuery(elem).dequeue()
return
)(1)