-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdropdown.coffee
154 lines (138 loc) · 3.85 KB
/
dropdown.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
ceri = require "ceri/lib/wrapper"
module.exports = ceri
mixins: [
require "ceri/lib/props"
require "ceri/lib/computed"
require "ceri/lib/style"
require "ceri/lib/animate"
require "ceri/lib/open"
require "ceri/lib/getViewportSize"
require "ceri/lib/getScrollPos"
]
props:
constrainWidth:
type: Boolean
overlay:
type: Boolean
gutter:
type: Number
default: 0
anchor:
type: String
onBody:
type: Boolean
hover:
type: Boolean
data: ->
position:
top: null
left: null
events:
mouseover:
el: "target"
active: -> @hover and !@openingOrOpen
cbs: "show"
destroy: true
mouseleave:
el: "target"
active: -> @hover
cbs: "hide"
destroy: true
click:
target:
active: -> !@hover and !@openingOrOpen
notPrevented: true
prevent: true
cbs: "show"
destroy: true
this:
notPrevented: true
prevent: true
cbs: "hide"
initStyle:
position: "absolute"
display: "block"
computedStyle:
this: ->
width: [@width,"px"]
boxSizing: if @width then "border-box" else null
left: [@position.left,"px"]
computed:
cAnchor: ->
return @anchor if @anchor
return "nw" if @overlay
return "sw"
target: ->
if @__placeholder.previousElementSibling
return @__placeholder.previousElementSibling
else
return @__parentElement
totalWidth: ->
if @constrainWidth
return @target.offsetWidth-@gutter
else
return @offsetWidth+@gutter
width: ->
return @totalWidth if @constrainWidth
return null
totalHeight: ->
if @overlay
return @offsetHeight
else
return @offsetHeight + @target.offsetHeight
methods:
enter: (o) ->
o.preserve = ["overflow","height"]
o.init = overflow: "hidden"
o.style =
height: [0,@offsetHeight, "px"]
opacity: [0,1]
if @position.asTop
o.init.top = @position.top + "px"
else
o.style.top = [@position.top+@offsetHeight,@position.top, "px"]
return @$animate(o)
leave: (o) ->
o.preserve = ["overflow","height"]
o.init = overflow: "hidden"
o.duration = 200
o.style =
height: [@offsetHeight,0, "px"]
opacity: [1,0]
unless @position.asTop
o.style.top = [@position.top, @position.top+@offsetHeight, "px"]
return @$animate(o)
onShow: ->
targetPos = @target.getBoundingClientRect()
windowSize = @getViewportSize()
asTop = true
if (@cAnchor[0] == "n" and @overlay) or (@cAnchor[0] == "s" and not @overlay)
asTop = targetPos.top + @totalHeight < windowSize.height
else
asTop = targetPos.bottom - @totalHeight < 0
asLeft = true
if @cAnchor[1] == "e"
asLeft = targetPos.right - @totalWidth < 0
else
asLeft = targetPos.left + @totalWidth < windowSize.width
top = if asTop then 0 else -@totalHeight
top += @target.offsetHeight unless asTop and @overlay
left = 0
if asLeft
left += @gutter
else
left -= @totalWidth - @target.offsetWidth
if @onBody
scroll = @getScrollPos()
top += scroll.top + targetPos.top
left += scroll.left + targetPos.left
else
parentStyle = getComputedStyle(@parentElement)
isPositioned = /relative|absolute|fixed/.test(parentStyle.getPropertyValue("position"))
if @parentElement == @target and isPositioned
left -= parseInt(parentStyle.getPropertyValue("border-left-width"))
top -= parseInt(parentStyle.getPropertyValue("border-top-width"))
else
top += @target.offsetTop
left += @target.offsetLeft
@position = top: top, left: left, asTop: asTop