in modules/closure/select/select.js [1989:2133]
function calculateMenuPositions(scope, element, opts) {
var
containerNode = element[0],
targetNode = opts.target[0].children[0], // target the label
parentNode = $document[0].body,
selectNode = opts.selectEl[0],
contentNode = opts.contentEl[0],
parentRect = parentNode.getBoundingClientRect(),
targetRect = targetNode.getBoundingClientRect(),
shouldOpenAroundTarget = false,
bounds = {
left: parentRect.left + SELECT_EDGE_MARGIN,
top: SELECT_EDGE_MARGIN,
bottom: parentRect.height - SELECT_EDGE_MARGIN,
right: parentRect.width - SELECT_EDGE_MARGIN - ($mdUtil.floatingScrollbars() ? 16 : 0)
},
spaceAvailable = {
top: targetRect.top - bounds.top,
left: targetRect.left - bounds.left,
right: bounds.right - (targetRect.left + targetRect.width),
bottom: bounds.bottom - (targetRect.top + targetRect.height)
},
maxWidth = parentRect.width - SELECT_EDGE_MARGIN * 2,
selectedNode = selectNode.querySelector('md-option[selected]'),
optionNodes = selectNode.getElementsByTagName('md-option'),
optgroupNodes = selectNode.getElementsByTagName('md-optgroup'),
isScrollable = calculateScrollable(element, contentNode),
centeredNode;
var loading = isPromiseLike(opts.loadingAsync);
if (!loading) {
// If a selected node, center around that
if (selectedNode) {
centeredNode = selectedNode;
// If there are option groups, center around the first option group
} else if (optgroupNodes.length) {
centeredNode = optgroupNodes[0];
// Otherwise - if we are not loading async - center around the first optionNode
} else if (optionNodes.length) {
centeredNode = optionNodes[0];
// In case there are no options, center on whatever's in there... (eg progress indicator)
} else {
centeredNode = contentNode.firstElementChild || contentNode;
}
} else {
// If loading, center on progress indicator
centeredNode = contentNode.firstElementChild || contentNode;
}
if (contentNode.offsetWidth > maxWidth) {
contentNode.style['max-width'] = maxWidth + 'px';
} else {
contentNode.style.maxWidth = null;
}
if (shouldOpenAroundTarget) {
contentNode.style['min-width'] = targetRect.width + 'px';
}
// Remove padding before we compute the position of the menu
if (isScrollable) {
selectNode.classList.add('md-overflow');
}
var focusedNode = centeredNode;
if ((focusedNode.tagName || '').toUpperCase() === 'MD-OPTGROUP') {
focusedNode = optionNodes[0] || contentNode.firstElementChild || contentNode;
centeredNode = focusedNode;
}
// Cache for autoFocus()
opts.focusedNode = focusedNode;
// Get the selectMenuRect *after* max-width is possibly set above
containerNode.style.display = 'block';
var selectMenuRect = selectNode.getBoundingClientRect();
var centeredRect = getOffsetRect(centeredNode);
if (centeredNode) {
var centeredStyle = $window.getComputedStyle(centeredNode);
centeredRect.paddingLeft = parseInt(centeredStyle.paddingLeft, 10) || 0;
centeredRect.paddingRight = parseInt(centeredStyle.paddingRight, 10) || 0;
}
if (isScrollable) {
var scrollBuffer = contentNode.offsetHeight / 2;
contentNode.scrollTop = centeredRect.top + centeredRect.height / 2 - scrollBuffer;
if (spaceAvailable.top < scrollBuffer) {
contentNode.scrollTop = Math.min(
centeredRect.top,
contentNode.scrollTop + scrollBuffer - spaceAvailable.top
);
} else if (spaceAvailable.bottom < scrollBuffer) {
contentNode.scrollTop = Math.max(
centeredRect.top + centeredRect.height - selectMenuRect.height,
contentNode.scrollTop - scrollBuffer + spaceAvailable.bottom
);
}
}
var left, top, transformOrigin, minWidth, fontSize;
if (shouldOpenAroundTarget) {
left = targetRect.left;
top = targetRect.top + targetRect.height;
transformOrigin = '50% 0';
if (top + selectMenuRect.height > bounds.bottom) {
top = targetRect.top - selectMenuRect.height;
transformOrigin = '50% 100%';
}
} else {
left = (targetRect.left + centeredRect.left - centeredRect.paddingLeft);
top = Math.floor(targetRect.top + targetRect.height / 2 - centeredRect.height / 2 -
centeredRect.top + contentNode.scrollTop) + 2;
transformOrigin = (centeredRect.left + targetRect.width / 2) + 'px ' +
(centeredRect.top + centeredRect.height / 2 - contentNode.scrollTop) + 'px 0px';
minWidth = Math.min(targetRect.width + centeredRect.paddingLeft + centeredRect.paddingRight, maxWidth);
fontSize = window.getComputedStyle(targetNode)['font-size'];
}
// Keep left and top within the window
var containerRect = containerNode.getBoundingClientRect();
var scaleX = Math.round(100 * Math.min(targetRect.width / selectMenuRect.width, 1.0)) / 100;
var scaleY = Math.round(100 * Math.min(targetRect.height / selectMenuRect.height, 1.0)) / 100;
return {
container: {
element: angular.element(containerNode),
styles: {
left: Math.floor(clamp(bounds.left, left, bounds.right - minWidth)),
top: Math.floor(clamp(bounds.top, top, bounds.bottom - containerRect.height)),
'min-width': minWidth,
'font-size': fontSize
}
},
dropDown: {
element: angular.element(selectNode),
styles: {
transformOrigin: transformOrigin,
transform: !opts.alreadyOpen ? $mdUtil.supplant('scale({0},{1})', [scaleX, scaleY]) : ""
}
}
};
}