UNPKG

8.71 kBJavaScriptView Raw
1'use strict';
2
3
4import { rtl as Rtl } from "./foundation.util.core";
5
6var Box = {
7 ImNotTouchingYou: ImNotTouchingYou,
8 OverlapArea: OverlapArea,
9 GetDimensions: GetDimensions,
10 GetOffsets: GetOffsets,
11 GetExplicitOffsets: GetExplicitOffsets
12}
13
14/**
15 * Compares the dimensions of an element to a container and determines collision events with container.
16 * @function
17 * @param {jQuery} element - jQuery object to test for collisions.
18 * @param {jQuery} parent - jQuery object to use as bounding container.
19 * @param {Boolean} lrOnly - set to true to check left and right values only.
20 * @param {Boolean} tbOnly - set to true to check top and bottom values only.
21 * @default if no parent object passed, detects collisions with `window`.
22 * @returns {Boolean} - true if collision free, false if a collision in any direction.
23 */
24function ImNotTouchingYou(element, parent, lrOnly, tbOnly, ignoreBottom) {
25 return OverlapArea(element, parent, lrOnly, tbOnly, ignoreBottom) === 0;
26};
27
28function OverlapArea(element, parent, lrOnly, tbOnly, ignoreBottom) {
29 var eleDims = GetDimensions(element),
30 topOver, bottomOver, leftOver, rightOver;
31 if (parent) {
32 var parDims = GetDimensions(parent);
33
34 bottomOver = (parDims.height + parDims.offset.top) - (eleDims.offset.top + eleDims.height);
35 topOver = eleDims.offset.top - parDims.offset.top;
36 leftOver = eleDims.offset.left - parDims.offset.left;
37 rightOver = (parDims.width + parDims.offset.left) - (eleDims.offset.left + eleDims.width);
38 }
39 else {
40 bottomOver = (eleDims.windowDims.height + eleDims.windowDims.offset.top) - (eleDims.offset.top + eleDims.height);
41 topOver = eleDims.offset.top - eleDims.windowDims.offset.top;
42 leftOver = eleDims.offset.left - eleDims.windowDims.offset.left;
43 rightOver = eleDims.windowDims.width - (eleDims.offset.left + eleDims.width);
44 }
45
46 bottomOver = ignoreBottom ? 0 : Math.min(bottomOver, 0);
47 topOver = Math.min(topOver, 0);
48 leftOver = Math.min(leftOver, 0);
49 rightOver = Math.min(rightOver, 0);
50
51 if (lrOnly) {
52 return leftOver + rightOver;
53 }
54 if (tbOnly) {
55 return topOver + bottomOver;
56 }
57
58 // use sum of squares b/c we care about overlap area.
59 return Math.sqrt((topOver * topOver) + (bottomOver * bottomOver) + (leftOver * leftOver) + (rightOver * rightOver));
60}
61
62/**
63 * Uses native methods to return an object of dimension values.
64 * @function
65 * @param {jQuery || HTML} element - jQuery object or DOM element for which to get the dimensions. Can be any element other that document or window.
66 * @returns {Object} - nested object of integer pixel values
67 * TODO - if element is window, return only those values.
68 */
69function GetDimensions(elem, test){
70 elem = elem.length ? elem[0] : elem;
71
72 if (elem === window || elem === document) {
73 throw new Error("I'm sorry, Dave. I'm afraid I can't do that.");
74 }
75
76 var rect = elem.getBoundingClientRect(),
77 parRect = elem.parentNode.getBoundingClientRect(),
78 winRect = document.body.getBoundingClientRect(),
79 winY = window.pageYOffset,
80 winX = window.pageXOffset;
81
82 return {
83 width: rect.width,
84 height: rect.height,
85 offset: {
86 top: rect.top + winY,
87 left: rect.left + winX
88 },
89 parentDims: {
90 width: parRect.width,
91 height: parRect.height,
92 offset: {
93 top: parRect.top + winY,
94 left: parRect.left + winX
95 }
96 },
97 windowDims: {
98 width: winRect.width,
99 height: winRect.height,
100 offset: {
101 top: winY,
102 left: winX
103 }
104 }
105 }
106}
107
108/**
109 * Returns an object of top and left integer pixel values for dynamically rendered elements,
110 * such as: Tooltip, Reveal, and Dropdown. Maintained for backwards compatibility, and where
111 * you don't know alignment, but generally from
112 * 6.4 forward you should use GetExplicitOffsets, as GetOffsets conflates position and alignment.
113 * @function
114 * @param {jQuery} element - jQuery object for the element being positioned.
115 * @param {jQuery} anchor - jQuery object for the element's anchor point.
116 * @param {String} position - a string relating to the desired position of the element, relative to it's anchor
117 * @param {Number} vOffset - integer pixel value of desired vertical separation between anchor and element.
118 * @param {Number} hOffset - integer pixel value of desired horizontal separation between anchor and element.
119 * @param {Boolean} isOverflow - if a collision event is detected, sets to true to default the element to full width - any desired offset.
120 * TODO alter/rewrite to work with `em` values as well/instead of pixels
121 */
122function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) {
123 console.log("NOTE: GetOffsets is deprecated in favor of GetExplicitOffsets and will be removed in 6.5");
124 switch (position) {
125 case 'top':
126 return Rtl() ?
127 GetExplicitOffsets(element, anchor, 'top', 'left', vOffset, hOffset, isOverflow) :
128 GetExplicitOffsets(element, anchor, 'top', 'right', vOffset, hOffset, isOverflow);
129 case 'bottom':
130 return Rtl() ?
131 GetExplicitOffsets(element, anchor, 'bottom', 'left', vOffset, hOffset, isOverflow) :
132 GetExplicitOffsets(element, anchor, 'bottom', 'right', vOffset, hOffset, isOverflow);
133 case 'center top':
134 return GetExplicitOffsets(element, anchor, 'top', 'center', vOffset, hOffset, isOverflow);
135 case 'center bottom':
136 return GetExplicitOffsets(element, anchor, 'bottom', 'center', vOffset, hOffset, isOverflow);
137 case 'center left':
138 return GetExplicitOffsets(element, anchor, 'left', 'center', vOffset, hOffset, isOverflow);
139 case 'center right':
140 return GetExplicitOffsets(element, anchor, 'right', 'center', vOffset, hOffset, isOverflow);
141 case 'left bottom':
142 return GetExplicitOffsets(element, anchor, 'bottom', 'left', vOffset, hOffset, isOverflow);
143 case 'right bottom':
144 return GetExplicitOffsets(element, anchor, 'bottom', 'right', vOffset, hOffset, isOverflow);
145 // Backwards compatibility... this along with the reveal and reveal full
146 // classes are the only ones that didn't reference anchor
147 case 'center':
148 return {
149 left: ($eleDims.windowDims.offset.left + ($eleDims.windowDims.width / 2)) - ($eleDims.width / 2) + hOffset,
150 top: ($eleDims.windowDims.offset.top + ($eleDims.windowDims.height / 2)) - ($eleDims.height / 2 + vOffset)
151 }
152 case 'reveal':
153 return {
154 left: ($eleDims.windowDims.width - $eleDims.width) / 2 + hOffset,
155 top: $eleDims.windowDims.offset.top + vOffset
156 }
157 case 'reveal full':
158 return {
159 left: $eleDims.windowDims.offset.left,
160 top: $eleDims.windowDims.offset.top
161 }
162 break;
163 default:
164 return {
165 left: (Rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width - hOffset: $anchorDims.offset.left + hOffset),
166 top: $anchorDims.offset.top + $anchorDims.height + vOffset
167 }
168
169 }
170
171}
172
173function GetExplicitOffsets(element, anchor, position, alignment, vOffset, hOffset, isOverflow) {
174 var $eleDims = GetDimensions(element),
175 $anchorDims = anchor ? GetDimensions(anchor) : null;
176
177 var topVal, leftVal;
178
179 // set position related attribute
180
181 switch (position) {
182 case 'top':
183 topVal = $anchorDims.offset.top - ($eleDims.height + vOffset);
184 break;
185 case 'bottom':
186 topVal = $anchorDims.offset.top + $anchorDims.height + vOffset;
187 break;
188 case 'left':
189 leftVal = $anchorDims.offset.left - ($eleDims.width + hOffset);
190 break;
191 case 'right':
192 leftVal = $anchorDims.offset.left + $anchorDims.width + hOffset;
193 break;
194 }
195
196
197 // set alignment related attribute
198 switch (position) {
199 case 'top':
200 case 'bottom':
201 switch (alignment) {
202 case 'left':
203 leftVal = $anchorDims.offset.left + hOffset;
204 break;
205 case 'right':
206 leftVal = $anchorDims.offset.left - $eleDims.width + $anchorDims.width - hOffset;
207 break;
208 case 'center':
209 leftVal = isOverflow ? hOffset : (($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2)) + hOffset;
210 break;
211 }
212 break;
213 case 'right':
214 case 'left':
215 switch (alignment) {
216 case 'bottom':
217 topVal = $anchorDims.offset.top - vOffset + $anchorDims.height - $eleDims.height;
218 break;
219 case 'top':
220 topVal = $anchorDims.offset.top + vOffset
221 break;
222 case 'center':
223 topVal = ($anchorDims.offset.top + vOffset + ($anchorDims.height / 2)) - ($eleDims.height / 2)
224 break;
225 }
226 break;
227 }
228 return {top: topVal, left: leftVal};
229}
230
231export {Box};