Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/third_party/closure/goog/positioning/positioning.js
4091 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Common positioning code.
9
*/
10
11
goog.provide('goog.positioning');
12
goog.provide('goog.positioning.Corner');
13
goog.provide('goog.positioning.CornerBit');
14
goog.provide('goog.positioning.Overflow');
15
goog.provide('goog.positioning.OverflowStatus');
16
17
goog.require('goog.asserts');
18
goog.require('goog.dom');
19
goog.require('goog.dom.TagName');
20
goog.require('goog.math.Coordinate');
21
goog.require('goog.math.Rect');
22
goog.require('goog.math.Size');
23
goog.require('goog.style');
24
goog.require('goog.style.bidi');
25
goog.requireType('goog.math.Box');
26
27
28
/**
29
* Enum for bits in the {@see goog.positioning.Corner) bitmap.
30
*
31
* @enum {number}
32
*/
33
goog.positioning.CornerBit = {
34
BOTTOM: 1,
35
CENTER: 2,
36
RIGHT: 4,
37
FLIP_RTL: 8
38
};
39
40
41
/**
42
* Enum for representing an element corner for positioning the popup.
43
*
44
* The START constants map to LEFT if element directionality is left
45
* to right and RIGHT if the directionality is right to left.
46
* Likewise END maps to RIGHT or LEFT depending on the directionality.
47
*
48
* @enum {number}
49
*/
50
goog.positioning.Corner = {
51
TOP_LEFT: 0,
52
TOP_RIGHT: goog.positioning.CornerBit.RIGHT,
53
BOTTOM_LEFT: goog.positioning.CornerBit.BOTTOM,
54
BOTTOM_RIGHT:
55
goog.positioning.CornerBit.BOTTOM | goog.positioning.CornerBit.RIGHT,
56
TOP_START: goog.positioning.CornerBit.FLIP_RTL,
57
TOP_END:
58
goog.positioning.CornerBit.FLIP_RTL | goog.positioning.CornerBit.RIGHT,
59
BOTTOM_START:
60
goog.positioning.CornerBit.BOTTOM | goog.positioning.CornerBit.FLIP_RTL,
61
BOTTOM_END: goog.positioning.CornerBit.BOTTOM |
62
goog.positioning.CornerBit.RIGHT | goog.positioning.CornerBit.FLIP_RTL,
63
TOP_CENTER: goog.positioning.CornerBit.CENTER,
64
BOTTOM_CENTER:
65
goog.positioning.CornerBit.BOTTOM | goog.positioning.CornerBit.CENTER
66
};
67
68
69
/**
70
* Enum for representing position handling in cases where the element would be
71
* positioned outside the viewport.
72
*
73
* @enum {number}
74
*/
75
goog.positioning.Overflow = {
76
/** Ignore overflow */
77
IGNORE: 0,
78
79
/** Try to fit horizontally in the viewport at all costs. */
80
ADJUST_X: 1,
81
82
/** If the element can't fit horizontally, report positioning failure. */
83
FAIL_X: 2,
84
85
/** Try to fit vertically in the viewport at all costs. */
86
ADJUST_Y: 4,
87
88
/** If the element can't fit vertically, report positioning failure. */
89
FAIL_Y: 8,
90
91
/** Resize the element's width to fit in the viewport. */
92
RESIZE_WIDTH: 16,
93
94
/** Resize the element's height to fit in the viewport. */
95
RESIZE_HEIGHT: 32,
96
97
/**
98
* If the anchor goes off-screen in the x-direction, position the movable
99
* element off-screen. Otherwise, try to fit horizontally in the viewport.
100
*/
101
ADJUST_X_EXCEPT_OFFSCREEN: 64 | 1,
102
103
/**
104
* If the anchor goes off-screen in the y-direction, position the movable
105
* element off-screen. Otherwise, try to fit vertically in the viewport.
106
*/
107
ADJUST_Y_EXCEPT_OFFSCREEN: 128 | 4
108
};
109
110
111
/**
112
* Enum for representing the outcome of a positioning call.
113
*
114
* @enum {number}
115
*/
116
goog.positioning.OverflowStatus = {
117
NONE: 0,
118
ADJUSTED_X: 1,
119
ADJUSTED_Y: 2,
120
WIDTH_ADJUSTED: 4,
121
HEIGHT_ADJUSTED: 8,
122
FAILED_LEFT: 16,
123
FAILED_RIGHT: 32,
124
FAILED_TOP: 64,
125
FAILED_BOTTOM: 128,
126
FAILED_OUTSIDE_VIEWPORT: 256,
127
/** Shorthand to check if a status code contains any fail code. */
128
FAILED: 16 | 32 | 64 | 128 | 256,
129
/** Shorthand to check if horizontal positioning failed. */
130
FAILED_HORIZONTAL: 16 | 32,
131
/** Shorthand to check if vertical positioning failed. */
132
FAILED_VERTICAL: 64 | 128,
133
};
134
135
136
/**
137
* Positions a movable element relative to an anchor element. The caller
138
* specifies the corners that should touch. This functions then moves the
139
* movable element accordingly.
140
*
141
* @param {Element} anchorElement The element that is the anchor for where
142
* the movable element should position itself.
143
* @param {goog.positioning.Corner} anchorElementCorner The corner of the
144
* anchorElement for positioning the movable element.
145
* @param {Element} movableElement The element to move.
146
* @param {goog.positioning.Corner} movableElementCorner The corner of the
147
* movableElement that that should be positioned adjacent to the anchor
148
* element.
149
* @param {goog.math.Coordinate=} opt_offset An offset specified in pixels.
150
* After the normal positioning algorithm is applied, the offset is then
151
* applied. Positive coordinates move the popup closer to the center of the
152
* anchor element. Negative coordinates move the popup away from the center
153
* of the anchor element.
154
* @param {goog.math.Box=} opt_margin A margin specified in pixels.
155
* After the normal positioning algorithm is applied and any offset, the
156
* margin is then applied. Positive coordinates move the popup away from the
157
* spot it was positioned towards its center. Negative coordinates move it
158
* towards the spot it was positioned away from its center.
159
* @param {?number=} opt_overflow Overflow handling mode. Defaults to IGNORE if
160
* not specified. Bitmap, {@see goog.positioning.Overflow}.
161
* @param {goog.math.Size=} opt_preferredSize The preferred size of the
162
* movableElement.
163
* @param {goog.math.Box=} opt_viewport Box object describing the dimensions of
164
* the viewport. The viewport is specified relative to offsetParent of
165
* `movableElement`. In other words, the viewport can be thought of as
166
* describing a "position: absolute" element contained in the offsetParent.
167
* It defaults to visible area of nearest scrollable ancestor of
168
* `movableElement` (see `goog.style.getVisibleRectForElement`).
169
* @return {goog.positioning.OverflowStatus} Status bitmap,
170
* {@see goog.positioning.OverflowStatus}.
171
*/
172
goog.positioning.positionAtAnchor = function(
173
anchorElement, anchorElementCorner, movableElement, movableElementCorner,
174
opt_offset, opt_margin, opt_overflow, opt_preferredSize, opt_viewport) {
175
'use strict';
176
goog.asserts.assert(movableElement);
177
var movableParentTopLeft =
178
goog.positioning.getOffsetParentPageOffset(movableElement);
179
180
// Get the visible part of the anchor element. anchorRect is
181
// relative to anchorElement's page.
182
var anchorRect = goog.positioning.getVisiblePart_(anchorElement);
183
184
// Translate anchorRect to be relative to movableElement's page.
185
goog.style.translateRectForAnotherFrame(
186
anchorRect, goog.dom.getDomHelper(anchorElement),
187
goog.dom.getDomHelper(movableElement));
188
189
// Offset based on which corner of the element we want to position against.
190
var corner =
191
goog.positioning.getEffectiveCorner(anchorElement, anchorElementCorner);
192
var offsetLeft = anchorRect.left;
193
if (corner & goog.positioning.CornerBit.RIGHT) {
194
offsetLeft += anchorRect.width;
195
} else if (corner & goog.positioning.CornerBit.CENTER) {
196
offsetLeft += anchorRect.width / 2;
197
}
198
199
// absolutePos is a candidate position relative to the
200
// movableElement's window.
201
var absolutePos = new goog.math.Coordinate(
202
offsetLeft, anchorRect.top +
203
(corner & goog.positioning.CornerBit.BOTTOM ? anchorRect.height : 0));
204
205
// Translate absolutePos to be relative to the offsetParent.
206
absolutePos =
207
goog.math.Coordinate.difference(absolutePos, movableParentTopLeft);
208
209
// Apply offset, if specified
210
if (opt_offset) {
211
absolutePos.x +=
212
(corner & goog.positioning.CornerBit.RIGHT ? -1 : 1) * opt_offset.x;
213
absolutePos.y +=
214
(corner & goog.positioning.CornerBit.BOTTOM ? -1 : 1) * opt_offset.y;
215
}
216
217
// Determine dimension of viewport.
218
var viewport;
219
if (opt_overflow) {
220
if (opt_viewport) {
221
viewport = opt_viewport;
222
} else {
223
viewport = goog.style.getVisibleRectForElement(movableElement);
224
if (viewport) {
225
viewport.top -= movableParentTopLeft.y;
226
viewport.right -= movableParentTopLeft.x;
227
viewport.bottom -= movableParentTopLeft.y;
228
viewport.left -= movableParentTopLeft.x;
229
}
230
}
231
}
232
233
return goog.positioning.positionAtCoordinate(
234
absolutePos, movableElement, movableElementCorner, opt_margin, viewport,
235
opt_overflow, opt_preferredSize);
236
};
237
238
239
/**
240
* Calculates the page offset of the given element's
241
* offsetParent. This value can be used to translate any x- and
242
* y-offset relative to the page to an offset relative to the
243
* offsetParent, which can then be used directly with as position
244
* coordinate for `positionWithCoordinate`.
245
* @param {!Element} movableElement The element to calculate.
246
* @return {!goog.math.Coordinate} The page offset, may be (0, 0).
247
*/
248
goog.positioning.getOffsetParentPageOffset = function(movableElement) {
249
'use strict';
250
// Ignore offset for the BODY element unless its position is non-static.
251
// For cases where the offset parent is HTML rather than the BODY (such as in
252
// IE strict mode) there's no need to get the position of the BODY as it
253
// doesn't affect the page offset.
254
var movableParentTopLeft;
255
var parent = /** @type {?} */ (movableElement).offsetParent;
256
if (parent) {
257
var isBody = parent.tagName == goog.dom.TagName.HTML ||
258
parent.tagName == goog.dom.TagName.BODY;
259
if (!isBody || goog.style.getComputedPosition(parent) != 'static') {
260
// Get the top-left corner of the parent, in page coordinates.
261
movableParentTopLeft = goog.style.getPageOffset(parent);
262
263
if (!isBody) {
264
movableParentTopLeft = goog.math.Coordinate.difference(
265
movableParentTopLeft,
266
new goog.math.Coordinate(
267
goog.style.bidi.getScrollLeft(parent), parent.scrollTop));
268
}
269
}
270
}
271
272
return movableParentTopLeft || new goog.math.Coordinate();
273
};
274
275
276
/**
277
* Returns intersection of the specified element and
278
* goog.style.getVisibleRectForElement for it.
279
*
280
* @param {Element} el The target element.
281
* @return {!goog.math.Rect} Intersection of getVisibleRectForElement
282
* and the current bounding rectangle of the element. If the
283
* intersection is empty, returns the bounding rectangle.
284
* @private
285
*/
286
goog.positioning.getVisiblePart_ = function(el) {
287
'use strict';
288
var rect = goog.style.getBounds(el);
289
var visibleBox = goog.style.getVisibleRectForElement(el);
290
if (visibleBox) {
291
rect.intersection(goog.math.Rect.createFromBox(visibleBox));
292
}
293
return rect;
294
};
295
296
297
/**
298
* Positions the specified corner of the movable element at the
299
* specified coordinate.
300
*
301
* @param {goog.math.Coordinate} absolutePos The coordinate to position the
302
* element at.
303
* @param {Element} movableElement The element to be positioned.
304
* @param {goog.positioning.Corner} movableElementCorner The corner of the
305
* movableElement that that should be positioned.
306
* @param {goog.math.Box=} opt_margin A margin specified in pixels.
307
* After the normal positioning algorithm is applied and any offset, the
308
* margin is then applied. Positive coordinates move the popup away from the
309
* spot it was positioned towards its center. Negative coordinates move it
310
* towards the spot it was positioned away from its center.
311
* @param {goog.math.Box=} opt_viewport Box object describing the dimensions of
312
* the viewport. Required if opt_overflow is specified.
313
* @param {?number=} opt_overflow Overflow handling mode. Defaults to IGNORE if
314
* not specified, {@see goog.positioning.Overflow}.
315
* @param {goog.math.Size=} opt_preferredSize The preferred size of the
316
* movableElement. Defaults to the current size.
317
* @return {goog.positioning.OverflowStatus} Status bitmap.
318
*/
319
goog.positioning.positionAtCoordinate = function(
320
absolutePos, movableElement, movableElementCorner, opt_margin, opt_viewport,
321
opt_overflow, opt_preferredSize) {
322
'use strict';
323
absolutePos = absolutePos.clone();
324
325
// Offset based on attached corner and desired margin.
326
var corner =
327
goog.positioning.getEffectiveCorner(movableElement, movableElementCorner);
328
var elementSize = goog.style.getSize(movableElement);
329
var size =
330
opt_preferredSize ? opt_preferredSize.clone() : elementSize.clone();
331
332
var positionResult = goog.positioning.getPositionAtCoordinate(
333
absolutePos, size, corner, opt_margin, opt_viewport, opt_overflow);
334
335
if (positionResult.status & goog.positioning.OverflowStatus.FAILED) {
336
return positionResult.status;
337
}
338
339
goog.style.setPosition(movableElement, positionResult.rect.getTopLeft());
340
size = positionResult.rect.getSize();
341
if (!goog.math.Size.equals(elementSize, size)) {
342
goog.style.setBorderBoxSize(movableElement, size);
343
}
344
345
return positionResult.status;
346
};
347
348
349
/**
350
* Computes the position for an element to be placed on-screen at the
351
* specified coordinates. Returns an object containing both the resulting
352
* rectangle, and the overflow status bitmap.
353
*
354
* @param {!goog.math.Coordinate} absolutePos The coordinate to position the
355
* element at.
356
* @param {!goog.math.Size} elementSize The size of the element to be
357
* positioned.
358
* @param {goog.positioning.Corner} elementCorner The corner of the
359
* movableElement that that should be positioned.
360
* @param {goog.math.Box=} opt_margin A margin specified in pixels.
361
* After the normal positioning algorithm is applied and any offset, the
362
* margin is then applied. Positive coordinates move the popup away from the
363
* spot it was positioned towards its center. Negative coordinates move it
364
* towards the spot it was positioned away from its center.
365
* @param {goog.math.Box=} opt_viewport Box object describing the dimensions of
366
* the viewport. Required if opt_overflow is specified.
367
* @param {?number=} opt_overflow Overflow handling mode. Defaults to IGNORE
368
* if not specified, {@see goog.positioning.Overflow}.
369
* @return {{rect:!goog.math.Rect, status:goog.positioning.OverflowStatus}}
370
* Object containing the computed position and status bitmap.
371
*/
372
goog.positioning.getPositionAtCoordinate = function(
373
absolutePos, elementSize, elementCorner, opt_margin, opt_viewport,
374
opt_overflow) {
375
'use strict';
376
absolutePos = absolutePos.clone();
377
elementSize = elementSize.clone();
378
var status = goog.positioning.OverflowStatus.NONE;
379
380
if (opt_margin || elementCorner != goog.positioning.Corner.TOP_LEFT) {
381
if (elementCorner & goog.positioning.CornerBit.RIGHT) {
382
absolutePos.x -= elementSize.width + (opt_margin ? opt_margin.right : 0);
383
} else if (elementCorner & goog.positioning.CornerBit.CENTER) {
384
absolutePos.x -= elementSize.width / 2;
385
} else if (opt_margin) {
386
absolutePos.x += opt_margin.left;
387
}
388
if (elementCorner & goog.positioning.CornerBit.BOTTOM) {
389
absolutePos.y -=
390
elementSize.height + (opt_margin ? opt_margin.bottom : 0);
391
} else if (opt_margin) {
392
absolutePos.y += opt_margin.top;
393
}
394
}
395
396
// Adjust position to fit inside viewport.
397
if (opt_overflow) {
398
status = opt_viewport ?
399
goog.positioning.adjustForViewport_(
400
absolutePos, elementSize, opt_viewport, opt_overflow) :
401
goog.positioning.OverflowStatus.FAILED_OUTSIDE_VIEWPORT;
402
}
403
404
var rect = new goog.math.Rect(0, 0, 0, 0);
405
rect.left = absolutePos.x;
406
rect.top = absolutePos.y;
407
rect.width = elementSize.width;
408
rect.height = elementSize.height;
409
return {rect: rect, status: status};
410
};
411
412
413
/**
414
* Adjusts the position and/or size of an element, identified by its position
415
* and size, to fit inside the viewport. If the position or size of the element
416
* is adjusted the pos or size objects, respectively, are modified.
417
*
418
* @param {goog.math.Coordinate} pos Position of element, updated if the
419
* position is adjusted.
420
* @param {goog.math.Size} size Size of element, updated if the size is
421
* adjusted.
422
* @param {goog.math.Box} viewport Bounding box describing the viewport.
423
* @param {number} overflow Overflow handling mode,
424
* {@see goog.positioning.Overflow}.
425
* @return {goog.positioning.OverflowStatus} Status bitmap,
426
* {@see goog.positioning.OverflowStatus}.
427
* @private
428
*/
429
goog.positioning.adjustForViewport_ = function(pos, size, viewport, overflow) {
430
'use strict';
431
var status = goog.positioning.OverflowStatus.NONE;
432
433
var ADJUST_X_EXCEPT_OFFSCREEN =
434
goog.positioning.Overflow.ADJUST_X_EXCEPT_OFFSCREEN;
435
var ADJUST_Y_EXCEPT_OFFSCREEN =
436
goog.positioning.Overflow.ADJUST_Y_EXCEPT_OFFSCREEN;
437
if ((overflow & ADJUST_X_EXCEPT_OFFSCREEN) == ADJUST_X_EXCEPT_OFFSCREEN &&
438
(pos.x < viewport.left || pos.x >= viewport.right)) {
439
overflow &= ~goog.positioning.Overflow.ADJUST_X;
440
}
441
if ((overflow & ADJUST_Y_EXCEPT_OFFSCREEN) == ADJUST_Y_EXCEPT_OFFSCREEN &&
442
(pos.y < viewport.top || pos.y >= viewport.bottom)) {
443
overflow &= ~goog.positioning.Overflow.ADJUST_Y;
444
}
445
446
// Left edge outside viewport, try to move it.
447
if (pos.x < viewport.left && overflow & goog.positioning.Overflow.ADJUST_X) {
448
pos.x = viewport.left;
449
status |= goog.positioning.OverflowStatus.ADJUSTED_X;
450
}
451
452
// Ensure object is inside the viewport width if required.
453
if (overflow & goog.positioning.Overflow.RESIZE_WIDTH) {
454
// Move left edge inside viewport.
455
var originalX = pos.x;
456
if (pos.x < viewport.left) {
457
pos.x = viewport.left;
458
status |= goog.positioning.OverflowStatus.WIDTH_ADJUSTED;
459
}
460
461
// Shrink width to inside right of viewport.
462
if (pos.x + size.width > viewport.right) {
463
// Set the width to be either the new maximum width within the viewport
464
// or the width originally within the viewport, whichever is less.
465
size.width = Math.min(
466
viewport.right - pos.x, originalX + size.width - viewport.left);
467
size.width = Math.max(size.width, 0);
468
status |= goog.positioning.OverflowStatus.WIDTH_ADJUSTED;
469
}
470
}
471
472
// Right edge outside viewport, try to move it.
473
if (pos.x + size.width > viewport.right &&
474
overflow & goog.positioning.Overflow.ADJUST_X) {
475
pos.x = Math.max(viewport.right - size.width, viewport.left);
476
status |= goog.positioning.OverflowStatus.ADJUSTED_X;
477
}
478
479
// Left or right edge still outside viewport, fail if the FAIL_X option was
480
// specified, ignore it otherwise.
481
if (overflow & goog.positioning.Overflow.FAIL_X) {
482
status |=
483
(pos.x < viewport.left ? goog.positioning.OverflowStatus.FAILED_LEFT :
484
0) |
485
(pos.x + size.width > viewport.right ?
486
goog.positioning.OverflowStatus.FAILED_RIGHT :
487
0);
488
}
489
490
// Top edge outside viewport, try to move it.
491
if (pos.y < viewport.top && overflow & goog.positioning.Overflow.ADJUST_Y) {
492
pos.y = viewport.top;
493
status |= goog.positioning.OverflowStatus.ADJUSTED_Y;
494
}
495
496
// Ensure object is inside the viewport height if required.
497
if (overflow & goog.positioning.Overflow.RESIZE_HEIGHT) {
498
// Move top edge inside viewport.
499
var originalY = pos.y;
500
if (pos.y < viewport.top) {
501
pos.y = viewport.top;
502
status |= goog.positioning.OverflowStatus.HEIGHT_ADJUSTED;
503
}
504
505
// Shrink height to inside bottom of viewport.
506
if (pos.y + size.height > viewport.bottom) {
507
// Set the height to be either the new maximum height within the viewport
508
// or the height originally within the viewport, whichever is less.
509
size.height = Math.min(
510
viewport.bottom - pos.y, originalY + size.height - viewport.top);
511
size.height = Math.max(size.height, 0);
512
status |= goog.positioning.OverflowStatus.HEIGHT_ADJUSTED;
513
}
514
}
515
516
// Bottom edge outside viewport, try to move it.
517
if (pos.y + size.height > viewport.bottom &&
518
overflow & goog.positioning.Overflow.ADJUST_Y) {
519
pos.y = Math.max(viewport.bottom - size.height, viewport.top);
520
status |= goog.positioning.OverflowStatus.ADJUSTED_Y;
521
}
522
523
// Top or bottom edge still outside viewport, fail if the FAIL_Y option was
524
// specified, ignore it otherwise.
525
if (overflow & goog.positioning.Overflow.FAIL_Y) {
526
status |=
527
(pos.y < viewport.top ? goog.positioning.OverflowStatus.FAILED_TOP :
528
0) |
529
(pos.y + size.height > viewport.bottom ?
530
goog.positioning.OverflowStatus.FAILED_BOTTOM :
531
0);
532
}
533
534
return /** @type {!goog.positioning.OverflowStatus} */ (status);
535
};
536
537
538
/**
539
* Returns an absolute corner (top/bottom left/right) given an absolute
540
* or relative (top/bottom start/end) corner and the direction of an element.
541
* Absolute corners remain unchanged.
542
* @param {Element} element DOM element to test for RTL direction.
543
* @param {goog.positioning.Corner} corner The popup corner used for
544
* positioning.
545
* @return {goog.positioning.Corner} Effective corner.
546
*/
547
goog.positioning.getEffectiveCorner = function(element, corner) {
548
'use strict';
549
return /** @type {goog.positioning.Corner} */ (
550
(corner & goog.positioning.CornerBit.FLIP_RTL &&
551
goog.style.isRightToLeft(element) ?
552
corner ^ goog.positioning.CornerBit.RIGHT :
553
corner) &
554
~goog.positioning.CornerBit.FLIP_RTL);
555
};
556
557
558
/**
559
* Returns the corner opposite the given one horizontally.
560
* @param {goog.positioning.Corner} corner The popup corner used to flip.
561
* @return {goog.positioning.Corner} The opposite corner horizontally.
562
*/
563
goog.positioning.flipCornerHorizontal = function(corner) {
564
'use strict';
565
return /** @type {goog.positioning.Corner} */ (
566
corner ^ goog.positioning.CornerBit.RIGHT);
567
};
568
569
570
/**
571
* Returns the corner opposite the given one vertically.
572
* @param {goog.positioning.Corner} corner The popup corner used to flip.
573
* @return {goog.positioning.Corner} The opposite corner vertically.
574
*/
575
goog.positioning.flipCornerVertical = function(corner) {
576
'use strict';
577
return /** @type {goog.positioning.Corner} */ (
578
corner ^ goog.positioning.CornerBit.BOTTOM);
579
};
580
581
582
/**
583
* Returns the corner opposite the given one horizontally and vertically.
584
* @param {goog.positioning.Corner} corner The popup corner used to flip.
585
* @return {goog.positioning.Corner} The opposite corner horizontally and
586
* vertically.
587
*/
588
goog.positioning.flipCorner = function(corner) {
589
'use strict';
590
return /** @type {goog.positioning.Corner} */ (
591
corner ^ goog.positioning.CornerBit.BOTTOM ^
592
goog.positioning.CornerBit.RIGHT);
593
};
594
595