Update JSON API
[src/app-framework-demo.git] / afm-client / bower_components / tether / coffee / constraint.coffee
1 {getOuterSize, getBounds, getSize, extend, updateClasses, defer} = @Tether.Utils
2
3 MIRROR_ATTACH =
4     left: 'right'
5     right: 'left'
6     top: 'bottom'
7     bottom: 'top'
8     middle: 'middle'
9
10 BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom']
11
12 getBoundingRect = (tether, to) ->
13   if to is 'scrollParent'
14     to = tether.scrollParent
15   else if to is 'window'
16     to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset]
17
18   if to is document
19     to = to.documentElement
20
21   if to.nodeType?
22     pos = size = getBounds to
23     style = getComputedStyle to
24
25     to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top]
26
27     for side, i in BOUNDS_FORMAT
28       side = side[0].toUpperCase() + side.substr(1)
29       if side in ['Top', 'Left']
30         to[i] += parseFloat style["border#{ side }Width"]
31       else
32         to[i] -= parseFloat style["border#{ side }Width"]
33
34   to
35
36 @Tether.modules.push
37   position: ({top, left, targetAttachment}) ->
38     return true unless @options.constraints
39
40     removeClass = (prefix) =>
41       @removeClass prefix
42       for side in BOUNDS_FORMAT
43         @removeClass "#{ prefix }-#{ side }"
44
45     {height, width} = @cache 'element-bounds', => getBounds @element
46
47     if width is 0 and height is 0 and @lastSize?
48       # Handle the item getting hidden as a result of our positioning without glitching
49       # the classes in and out
50       {width, height} = @lastSize
51
52     targetSize = @cache 'target-bounds', => @getTargetBounds()
53     targetHeight = targetSize.height
54     targetWidth = targetSize.width
55
56     tAttachment = {}
57     eAttachment = {}
58
59     allClasses = [@getClass('pinned'), @getClass('out-of-bounds')]
60     for constraint in @options.constraints
61       allClasses.push(constraint.outOfBoundsClass) if constraint.outOfBoundsClass
62       allClasses.push(constraint.pinnedClass) if constraint.pinnedClass
63
64     for cls in allClasses
65       for side in ['left', 'top', 'right', 'bottom']
66         allClasses.push "#{ cls }-#{ side }"
67
68     addClasses = []
69
70     tAttachment = extend {}, targetAttachment
71     eAttachment = extend {}, @attachment
72
73     for constraint in @options.constraints
74       {to, attachment, pin} = constraint
75
76       attachment ?= ''
77
78       if ' ' in attachment
79         [changeAttachY, changeAttachX] = attachment.split(' ')
80       else
81         changeAttachX = changeAttachY = attachment
82
83       bounds = getBoundingRect @, to
84
85       if changeAttachY in ['target', 'both']
86         if (top < bounds[1] and tAttachment.top is 'top')
87           top += targetHeight
88           tAttachment.top = 'bottom'
89
90         if (top + height > bounds[3] and tAttachment.top is 'bottom')
91           top -= targetHeight
92           tAttachment.top = 'top'
93
94       if changeAttachY is 'together'
95         if top < bounds[1] and tAttachment.top is 'top'
96           if eAttachment.top is 'bottom'
97             top += targetHeight
98             tAttachment.top = 'bottom'
99
100             top += height
101             eAttachment.top = 'top'
102           else if eAttachment.top is 'top'
103             top += targetHeight
104             tAttachment.top = 'bottom'
105
106             top -= height
107             eAttachment.top = 'bottom'
108
109         if top + height > bounds[3] and tAttachment.top is 'bottom'
110           if eAttachment.top is 'top'
111             top -= targetHeight
112             tAttachment.top = 'top'
113
114             top -= height
115             eAttachment.top = 'bottom'
116           else if eAttachment.top is 'bottom'
117             top -= targetHeight
118             tAttachment.top = 'top'
119
120             top += height
121             eAttachment.top = 'top'
122
123         if tAttachment.top is 'middle'
124           if top + height > bounds[3] and eAttachment.top is 'top'
125             top -= height
126             eAttachment.top = 'bottom'
127
128           else if top < bounds[1] and eAttachment.top is 'bottom'
129             top += height
130             eAttachment.top = 'top'
131
132       if changeAttachX in ['target', 'both']
133         if (left < bounds[0] and tAttachment.left is 'left')
134           left += targetWidth
135           tAttachment.left = 'right'
136
137         if (left + width > bounds[2] and tAttachment.left is 'right')
138           left -= targetWidth
139           tAttachment.left = 'left'
140
141       if changeAttachX is 'together'
142         if left < bounds[0] and tAttachment.left is 'left'
143           if eAttachment.left is 'right'
144             left += targetWidth
145             tAttachment.left = 'right'
146
147             left += width
148             eAttachment.left = 'left'
149
150           else if eAttachment.left is 'left'
151             left += targetWidth
152             tAttachment.left = 'right'
153
154             left -= width
155             eAttachment.left = 'right'
156
157         else if left + width > bounds[2] and tAttachment.left is 'right'
158           if eAttachment.left is 'left'
159             left -= targetWidth
160             tAttachment.left = 'left'
161
162             left -= width
163             eAttachment.left = 'right'
164
165           else if eAttachment.left is 'right'
166             left -= targetWidth
167             tAttachment.left = 'left'
168
169             left += width
170             eAttachment.left = 'left'
171
172         else if tAttachment.left is 'center'
173           if left + width > bounds[2] and eAttachment.left is 'left'
174             left -= width
175             eAttachment.left = 'right'
176
177           else if left < bounds[0] and eAttachment.left is 'right'
178             left += width
179             eAttachment.left = 'left'
180
181       if changeAttachY in ['element', 'both']
182         if (top < bounds[1] and eAttachment.top is 'bottom')
183           top += height
184           eAttachment.top = 'top'
185
186         if (top + height > bounds[3] and eAttachment.top is 'top')
187           top -= height
188           eAttachment.top = 'bottom'
189
190       if changeAttachX in ['element', 'both']
191         if (left < bounds[0] and eAttachment.left is 'right')
192           left += width
193           eAttachment.left = 'left'
194
195         if (left + width > bounds[2] and eAttachment.left is 'left')
196           left -= width
197           eAttachment.left = 'right'
198
199       if typeof pin is 'string'
200         pin = (p.trim() for p in pin.split ',')
201       else if pin is true
202         pin = ['top', 'left', 'right', 'bottom']
203       
204       pin or= []
205
206       pinned = []
207       oob = []
208       if top < bounds[1]
209         if 'top' in pin
210           top = bounds[1]
211           pinned.push 'top'
212         else
213           oob.push 'top'
214
215       if top + height > bounds[3]
216         if 'bottom' in pin
217           top = bounds[3] - height
218           pinned.push 'bottom'
219         else
220           oob.push 'bottom'
221
222       if left < bounds[0]
223         if 'left' in pin
224           left = bounds[0]
225           pinned.push 'left'
226         else
227           oob.push 'left'
228
229       if left + width > bounds[2]
230         if 'right' in pin
231           left = bounds[2] - width
232           pinned.push 'right'
233         else
234           oob.push 'right'
235
236       if pinned.length
237         pinnedClass = @options.pinnedClass ? @getClass('pinned')
238         addClasses.push pinnedClass
239         for side in pinned
240           addClasses.push "#{ pinnedClass }-#{ side }"
241
242       if oob.length
243         oobClass = @options.outOfBoundsClass ? @getClass('out-of-bounds')
244         addClasses.push oobClass
245         for side in oob
246           addClasses.push "#{ oobClass }-#{ side }"
247
248       if 'left' in pinned or 'right' in pinned
249         eAttachment.left = tAttachment.left = false
250       if 'top' in pinned or 'bottom' in pinned
251         eAttachment.top = tAttachment.top = false
252
253       if tAttachment.top isnt targetAttachment.top or tAttachment.left isnt targetAttachment.left or eAttachment.top isnt @attachment.top or eAttachment.left isnt @attachment.left
254         @updateAttachClasses eAttachment, tAttachment
255
256     defer =>
257       updateClasses @target, addClasses, allClasses
258       updateClasses @element, addClasses, allClasses
259
260     {top, left}