|
|
|
/**
|
|
|
|
* 对DOM操作的通用函数
|
|
|
|
*/
|
|
|
|
import { each, isEmpty, isNull } from "../../2.base";
|
|
|
|
|
|
|
|
export function ready(fn) {
|
|
|
|
BI.Widget._renderEngine.createElement(document).ready(fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function patchProps(fromElement, toElement) {
|
|
|
|
const elemData = BI.jQuery._data(fromElement[0]);
|
|
|
|
const events = elemData.events;
|
|
|
|
each(events, (eventKey, event) => {
|
|
|
|
each(event, (i, handler) => {
|
|
|
|
toElement.on(eventKey + (handler.namespace ? (`.${handler.namespace}`) : ""), handler);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
const fromChildren = fromElement.children(), toChildren = toElement.children();
|
|
|
|
if (fromChildren.length !== toChildren.length) {
|
|
|
|
throw new Error("不匹配");
|
|
|
|
}
|
|
|
|
each(fromChildren, (i, child) => {
|
|
|
|
patchProps(BI.jQuery(child), BI.jQuery(toChildren[i]));
|
|
|
|
});
|
|
|
|
each(fromElement.data("__widgets"), (i, widget) => {
|
|
|
|
widget.element = toElement;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 把dom数组或元素悬挂起来,使其不对html产生影响
|
|
|
|
* @param dom
|
|
|
|
*/
|
|
|
|
export function hang(doms) {
|
|
|
|
if (isEmpty(doms)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const frag = BI.Widget._renderEngine.createFragment();
|
|
|
|
each(doms, (i, dom) => {
|
|
|
|
dom instanceof BI.Widget && (dom = dom.element);
|
|
|
|
dom instanceof BI.$ && dom[0] && frag.appendChild(dom[0]);
|
|
|
|
});
|
|
|
|
|
|
|
|
return frag;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isExist(obj) {
|
|
|
|
return BI.Widget._renderEngine.createElement("body").find(obj.element).length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 预加载图片
|
|
|
|
export function preloadImages(srcArray, onload) {
|
|
|
|
let count = 0;
|
|
|
|
const images = [];
|
|
|
|
|
|
|
|
function complete() {
|
|
|
|
count++;
|
|
|
|
if (count >= srcArray.length) {
|
|
|
|
onload();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
each(srcArray, (i, src) => {
|
|
|
|
images[i] = new Image();
|
|
|
|
images[i].src = src;
|
|
|
|
images[i].onload = function () {
|
|
|
|
complete();
|
|
|
|
};
|
|
|
|
images[i].onerror = function () {
|
|
|
|
complete();
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getTextSizeWidth(text, fontSize = 12) {
|
|
|
|
const span = BI.Widget._renderEngine.createElement("<span></span>").addClass("text-width-span").appendTo("body");
|
|
|
|
|
|
|
|
fontSize = `${fontSize}px`;
|
|
|
|
|
|
|
|
span.css("font-size", fontSize).text(text);
|
|
|
|
|
|
|
|
const width = span.width();
|
|
|
|
span.remove();
|
|
|
|
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getTextSizeHeight(text, fontSize = 12) {
|
|
|
|
const span = BI.Widget._renderEngine.createElement("<span></span>").addClass("text-width-span").appendTo("body");
|
|
|
|
|
|
|
|
fontSize = `${fontSize}px`;
|
|
|
|
|
|
|
|
span.css("font-size", fontSize).text(text);
|
|
|
|
|
|
|
|
const height = span.height();
|
|
|
|
span.remove();
|
|
|
|
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取滚动条的宽度,页面display: none时候获取到的为0
|
|
|
|
let _scrollWidth = null;
|
|
|
|
|
|
|
|
export function getScrollWidth() {
|
|
|
|
if (isNull(_scrollWidth) || _scrollWidth === 0) {
|
|
|
|
const ul = BI.Widget._renderEngine.createElement("<div>").width(50).height(50)
|
|
|
|
.css({
|
|
|
|
position: "absolute",
|
|
|
|
top: "-9999px",
|
|
|
|
overflow: "scroll",
|
|
|
|
})
|
|
|
|
.appendTo("body");
|
|
|
|
_scrollWidth = ul[0].offsetWidth - ul[0].clientWidth;
|
|
|
|
ul.destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
return _scrollWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getImage(param, fillStyle, backgroundColor) {
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
const ratio = 2;
|
|
|
|
BI.Widget._renderEngine.createElement("body").append(canvas);
|
|
|
|
|
|
|
|
const ctx = canvas.getContext("2d");
|
|
|
|
ctx.font = "12px Helvetica Neue,Arial,PingFang SC,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Heiti,黑体,sans-serif";
|
|
|
|
const w = ctx.measureText(param).width + 4;
|
|
|
|
canvas.width = w * ratio;
|
|
|
|
canvas.height = 16 * ratio;
|
|
|
|
ctx.font = `${12 * ratio}px Helvetica Neue,Arial,PingFang SC,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Heiti,黑体,sans-serif`;
|
|
|
|
ctx.fillStyle = fillStyle || "#3685f2";
|
|
|
|
ctx.textBaseline = "middle";
|
|
|
|
// ctx.fillStyle = "#EAF2FD";
|
|
|
|
ctx.fillText(param, 2 * ratio, 9 * ratio);
|
|
|
|
BI.Widget._renderEngine.createElement(canvas).destroy();
|
|
|
|
const backColor = backgroundColor || "rgba(54, 133, 242, 0.1)";
|
|
|
|
|
|
|
|
// IE可以放大缩小所以要固定最大最小宽高
|
|
|
|
return {
|
|
|
|
width: w,
|
|
|
|
height: 16,
|
|
|
|
src: canvas.toDataURL("image/png"),
|
|
|
|
style: `background-color: ${backColor};vertical-align: middle; margin: 0 1px; width:${w}px;height: 16px; max-width:${w}px;max-height: 16px; min-width:${w}px;min-height: 16px`,
|
|
|
|
param,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getLeftPosition(combo, popup, extraWidth, container) {
|
|
|
|
const el = combo.element;
|
|
|
|
const popupEl = popup.element;
|
|
|
|
const elRect = el[0].getBoundingClientRect();
|
|
|
|
const popupElRect = popupEl[0].getBoundingClientRect();
|
|
|
|
const containerRect = container ? container.getBoundingClientRect() : { left: 0 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
left: elRect.left - containerRect.left - popupElRect.width - (extraWidth || 0),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getInnerLeftPosition(combo, popup, extraWidth) {
|
|
|
|
return {
|
|
|
|
left: combo.element.offset().left + (extraWidth || 0),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getRightPosition(combo, popup, extraWidth, container) {
|
|
|
|
const el = combo.element;
|
|
|
|
const elRect = el[0].getBoundingClientRect();
|
|
|
|
const containerRect = container ? container.getBoundingClientRect() : { left: 0 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
left: elRect.left + elRect.width - containerRect.left + (extraWidth || 0),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getInnerRightPosition(combo, popup, extraWidth) {
|
|
|
|
const el = combo.element, viewBounds = popup.element.bounds();
|
|
|
|
|
|
|
|
return {
|
|
|
|
left: el.offset().left + el.outerWidth() - viewBounds.width - (extraWidth || 0),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getTopPosition(combo, popup, extraHeight, container) {
|
|
|
|
const el = combo.element;
|
|
|
|
const popupEl = popup.element;
|
|
|
|
const elRect = el[0].getBoundingClientRect();
|
|
|
|
const popupElRect = popupEl[0].getBoundingClientRect();
|
|
|
|
const containerRect = container ? container.getBoundingClientRect() : { top: 0 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
top: elRect.top - containerRect.top - popupElRect.height - (extraHeight || 0),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getBottomPosition(combo, popup, extraHeight, container) {
|
|
|
|
const el = combo.element;
|
|
|
|
const elRect = el[0].getBoundingClientRect();
|
|
|
|
const containerRect = container ? container.getBoundingClientRect() : { top: 0 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
top: elRect.top - containerRect.top + elRect.height + (extraHeight || 0),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isLeftSpaceEnough(combo, popup, extraWidth) {
|
|
|
|
return getLeftPosition(combo, popup, extraWidth).left >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isInnerLeftSpaceEnough(combo, popup, extraWidth) {
|
|
|
|
const viewBounds = popup.element.bounds(),
|
|
|
|
windowBounds = BI.Widget._renderEngine.createElement("body").bounds();
|
|
|
|
|
|
|
|
return getInnerLeftPosition(combo, popup, extraWidth).left + viewBounds.width <= windowBounds.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isRightSpaceEnough(combo, popup, extraWidth) {
|
|
|
|
const viewBounds = popup.element[0].getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
|
|
|
|
return getRightPosition(combo, popup, extraWidth).left + viewBounds.width <= viewportBounds.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isInnerRightSpaceEnough(combo, popup, extraWidth) {
|
|
|
|
return getInnerRightPosition(combo, popup, extraWidth).left >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isTopSpaceEnough(combo, popup, extraHeight) {
|
|
|
|
return getTopPosition(combo, popup, extraHeight).top >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isBottomSpaceEnough(combo, popup, extraHeight) {
|
|
|
|
const viewBounds = popup.element[0].getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
|
|
|
|
return getBottomPosition(combo, popup, extraHeight).top + viewBounds.height <= viewportBounds.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isRightSpaceLarger(combo) {
|
|
|
|
const comboBounds = combo.element[0].getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
|
|
|
|
return viewportBounds.width - comboBounds.right >= comboBounds.left;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isBottomSpaceLarger(combo) {
|
|
|
|
const comboBounds = combo.element[0].getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
|
|
|
|
return viewportBounds.height - comboBounds.bottom >= comboBounds.top;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function _getLeftAlignPosition(combo, popup, extraWidth, container) {
|
|
|
|
const comboRect = combo.element[0].getBoundingClientRect(),
|
|
|
|
popupRect = popup.element[0].getBoundingClientRect(),
|
|
|
|
viewportRect = document.documentElement.getBoundingClientRect(),
|
|
|
|
containerRect = container ? container.getBoundingClientRect() : { left: 0 };
|
|
|
|
let left = comboRect.left - containerRect.left + extraWidth;
|
|
|
|
|
|
|
|
if (comboRect.left + popupRect.width > viewportRect.width) {
|
|
|
|
left = viewportRect.width - popupRect.width - containerRect.left;
|
|
|
|
}
|
|
|
|
|
|
|
|
return left;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getLeftAlignPosition(combo, popup, extraWidth, container) {
|
|
|
|
let left = this._getLeftAlignPosition(combo, popup, extraWidth, container);
|
|
|
|
let dir = "";
|
|
|
|
// 如果放不下,优先使用RightAlign, 如果RightAlign也放不下, 再使用left=0
|
|
|
|
const containerRect = container ? container.getBoundingClientRect() : { left: 0 };
|
|
|
|
if (left + containerRect.left < 0) {
|
|
|
|
left = this._getRightAlignPosition(combo, popup, extraWidth);
|
|
|
|
dir = "left";
|
|
|
|
}
|
|
|
|
if (left + containerRect.left < 0) {
|
|
|
|
left = 0 - containerRect.left;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
left,
|
|
|
|
dir: dir || "right",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getLeftAdaptPosition(combo, popup, extraWidth, container) {
|
|
|
|
if (isLeftSpaceEnough(combo, popup, extraWidth, container)) {
|
|
|
|
return getLeftPosition(combo, popup, extraWidth, container);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
left: 0,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function _getRightAlignPosition(combo, popup, extraWidth, container) {
|
|
|
|
const comboBounds = combo.element[0].getBoundingClientRect(),
|
|
|
|
viewBounds = popup.element[0].getBoundingClientRect(),
|
|
|
|
containerRect = container ? container.getBoundingClientRect() : { left: 0 };
|
|
|
|
|
|
|
|
return comboBounds.left + comboBounds.width - viewBounds.width - extraWidth - containerRect.left;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getRightAlignPosition(combo, popup, extraWidth, container) {
|
|
|
|
let left = this._getRightAlignPosition(combo, popup, extraWidth, container);
|
|
|
|
let dir = "";
|
|
|
|
// 如果放不下,优先使用LeftAlign, 如果LeftAlign也放不下, 再使用left=0
|
|
|
|
if (left < 0) {
|
|
|
|
left = this._getLeftAlignPosition(combo, popup, extraWidth, container);
|
|
|
|
dir = "right";
|
|
|
|
}
|
|
|
|
if (left < 0) {
|
|
|
|
left = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
left,
|
|
|
|
dir: dir || "left",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getRightAdaptPosition(combo, popup, extraWidth, container) {
|
|
|
|
if (isRightSpaceEnough(combo, popup, extraWidth, container)) {
|
|
|
|
return getRightPosition(combo, popup, extraWidth, container);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
left: document.documentElement.getBoundingClientRect().width - popup.element[0].getBoundingClientRect().width - container.getBoundingClientRect().left,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getTopAlignPosition(combo, popup, extraHeight, needAdaptHeight, container) {
|
|
|
|
const comboBounds = combo.element[0].getBoundingClientRect(),
|
|
|
|
popupBounds = popup.element[0].getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect(),
|
|
|
|
containerBounds = container ? container.getBoundingClientRect() : { top: 0 };
|
|
|
|
let top, adaptHeight, dir;
|
|
|
|
if (isBottomSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) {
|
|
|
|
top = comboBounds.top - containerBounds.top + extraHeight;
|
|
|
|
} else if (needAdaptHeight) {
|
|
|
|
top = comboBounds.top - containerBounds.top + extraHeight;
|
|
|
|
adaptHeight = viewportBounds.height - comboBounds.top;
|
|
|
|
} else if (isTopSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) {
|
|
|
|
// 下方空间不足且不允许调整高度的情况下,优先使用上对齐
|
|
|
|
top = comboBounds.top + comboBounds.height - popupBounds.height - containerBounds.top - extraHeight;
|
|
|
|
dir = "top";
|
|
|
|
} else {
|
|
|
|
top = viewportBounds.height - popupBounds.height;
|
|
|
|
if (top < extraHeight) {
|
|
|
|
adaptHeight = viewportBounds.height - extraHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (top < extraHeight) {
|
|
|
|
top = extraHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
return adaptHeight ? {
|
|
|
|
top,
|
|
|
|
adaptHeight,
|
|
|
|
dir: dir || "bottom",
|
|
|
|
} : {
|
|
|
|
top,
|
|
|
|
dir: dir || "bottom",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getTopAdaptPosition(combo, popup, extraHeight, needAdaptHeight, positionRelativeElement) {
|
|
|
|
const comboBounds = combo.element[0].getBoundingClientRect(),
|
|
|
|
popupBounds = popup.element[0].getBoundingClientRect(),
|
|
|
|
positionRelativeElementRect = positionRelativeElement.getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
if (isTopSpaceEnough(combo, popup, extraHeight)) {
|
|
|
|
return getTopPosition(combo, popup, extraHeight);
|
|
|
|
}
|
|
|
|
if (needAdaptHeight) {
|
|
|
|
return {
|
|
|
|
top: 0 - positionRelativeElementRect.top,
|
|
|
|
adaptHeight: comboBounds.top - extraHeight,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (popupBounds.height + extraHeight > viewportBounds.height) {
|
|
|
|
return {
|
|
|
|
top: 0 - positionRelativeElementRect.top,
|
|
|
|
adaptHeight: viewportBounds.height - extraHeight,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
top: 0 - positionRelativeElementRect.top,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getBottomAlignPosition(combo, popup, extraHeight, needAdaptHeight, container) {
|
|
|
|
const comboBounds = combo.element[0].getBoundingClientRect(),
|
|
|
|
popupBounds = popup.element[0].getBoundingClientRect(),
|
|
|
|
windowBounds = BI.Widget._renderEngine.createElement("body").bounds(),
|
|
|
|
containerBounds = container ? container.getBoundingClientRect() : { top: 0 };
|
|
|
|
let top, adaptHeight, dir;
|
|
|
|
if (isTopSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) {
|
|
|
|
top = comboBounds.top + comboBounds.height - containerBounds.top - popupBounds.height;
|
|
|
|
} else if (needAdaptHeight) {
|
|
|
|
top = 0 - containerBounds.top;
|
|
|
|
adaptHeight = comboBounds.top + comboBounds.height - extraHeight;
|
|
|
|
} else if (isBottomSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) {
|
|
|
|
// 上方空间不足且不允许调整高度的情况下,优先使用下对齐
|
|
|
|
top = comboBounds.top - containerBounds.top + extraHeight;
|
|
|
|
dir = "bottom";
|
|
|
|
} else {
|
|
|
|
top = 0;
|
|
|
|
if (popupBounds.height + extraHeight > windowBounds.height) {
|
|
|
|
adaptHeight = windowBounds.height - extraHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (top + containerBounds.top < 0) {
|
|
|
|
top = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return adaptHeight ? {
|
|
|
|
top,
|
|
|
|
adaptHeight,
|
|
|
|
dir: dir || "top",
|
|
|
|
} : {
|
|
|
|
top,
|
|
|
|
dir: dir || "top",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getBottomAdaptPosition(combo, popup, extraHeight, needAdaptHeight, positionRelativeElement) {
|
|
|
|
const comboBounds = combo.element[0].getBoundingClientRect(),
|
|
|
|
popupBounds = popup.element[0].getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect(),
|
|
|
|
positionRelativeElementRect = positionRelativeElement.getBoundingClientRect();
|
|
|
|
if (isBottomSpaceEnough(combo, popup, extraHeight)) {
|
|
|
|
return getBottomPosition(combo, popup, extraHeight, positionRelativeElement);
|
|
|
|
}
|
|
|
|
if (needAdaptHeight) {
|
|
|
|
return {
|
|
|
|
top: comboBounds.top + comboBounds.height + extraHeight - positionRelativeElementRect.top,
|
|
|
|
adaptHeight: viewportBounds.height - comboBounds.top - comboBounds.height - extraHeight,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (popupBounds.height + extraHeight > viewportBounds.height) {
|
|
|
|
return {
|
|
|
|
top: extraHeight - positionRelativeElementRect.top,
|
|
|
|
adaptHeight: viewportBounds.height - extraHeight,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
top: viewportBounds.height - popupBounds.height - extraHeight - positionRelativeElementRect.top,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getCenterAdaptPosition(combo, popup, positionRelativeElement) {
|
|
|
|
const comboRect = combo.element[0].getBoundingClientRect(),
|
|
|
|
popupRect = popup.element[0].getBoundingClientRect(),
|
|
|
|
positionRelativeElementRect = positionRelativeElement.getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
let left;
|
|
|
|
if (comboRect.left + comboRect.width / 2 + popupRect.width / 2 > viewportBounds.width) {
|
|
|
|
left = viewportBounds.width - popupRect.width - positionRelativeElementRect.left;
|
|
|
|
} else {
|
|
|
|
left = comboRect.left + (comboRect.width - popupRect.width) / 2 - positionRelativeElementRect.left;
|
|
|
|
}
|
|
|
|
if (left + positionRelativeElementRect.left < 0) {
|
|
|
|
left = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
left,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getMiddleAdaptPosition(combo, popup, positionRelativeElement) {
|
|
|
|
const comboRect = combo.element[0].getBoundingClientRect(),
|
|
|
|
popupRect = popup.element[0].getBoundingClientRect(),
|
|
|
|
positionRelativeElementRect = positionRelativeElement.getBoundingClientRect(),
|
|
|
|
viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
|
|
|
|
let top;
|
|
|
|
if (comboRect.top + comboRect.height / 2 + popupRect.height / 2 > viewportBounds.height) {
|
|
|
|
top = viewportBounds.height - popupRect.height - positionRelativeElementRect.top;
|
|
|
|
} else {
|
|
|
|
top = comboRect.top + (comboRect.height - popupRect.height) / 2 - positionRelativeElementRect.top;
|
|
|
|
}
|
|
|
|
if (top + positionRelativeElementRect.top < 0) {
|
|
|
|
top = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
top,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getComboPositionByDirections(combo, popup, extraWidth, extraHeight, needAdaptHeight, directions, container) {
|
|
|
|
extraWidth || (extraWidth = 0);
|
|
|
|
extraHeight || (extraHeight = 0);
|
|
|
|
let i, direct;
|
|
|
|
const leftRight = [], topBottom = [], innerLeftRight = [];
|
|
|
|
let isNeedAdaptHeight = false, tbFirst = false, lrFirst = false;
|
|
|
|
let left, top, pos, firstDir = directions[0];
|
|
|
|
for (i = 0; i < directions.length; i++) {
|
|
|
|
direct = directions[i];
|
|
|
|
switch (direct) {
|
|
|
|
case "left":
|
|
|
|
leftRight.push(direct);
|
|
|
|
break;
|
|
|
|
case "right":
|
|
|
|
leftRight.push(direct);
|
|
|
|
break;
|
|
|
|
case "top":
|
|
|
|
topBottom.push(direct);
|
|
|
|
break;
|
|
|
|
case "bottom":
|
|
|
|
topBottom.push(direct);
|
|
|
|
break;
|
|
|
|
case "innerLeft":
|
|
|
|
innerLeftRight.push(direct);
|
|
|
|
break;
|
|
|
|
case "innerRight":
|
|
|
|
innerLeftRight.push(direct);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < directions.length; i++) {
|
|
|
|
direct = directions[i];
|
|
|
|
switch (direct) {
|
|
|
|
case "left":
|
|
|
|
if (!isNeedAdaptHeight) {
|
|
|
|
var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? 0 : extraHeight;
|
|
|
|
if (isLeftSpaceEnough(combo, popup, tW)) {
|
|
|
|
left = getLeftPosition(combo, popup, tW, container).left;
|
|
|
|
if (topBottom[0] === "bottom") {
|
|
|
|
pos = getTopAlignPosition(combo, popup, tH, needAdaptHeight, container);
|
|
|
|
} else {
|
|
|
|
pos = getBottomAlignPosition(combo, popup, tH, needAdaptHeight, container);
|
|
|
|
}
|
|
|
|
pos.dir = `left,${pos.dir}`;
|
|
|
|
if (tbFirst) {
|
|
|
|
pos.change = "left";
|
|
|
|
}
|
|
|
|
pos.left = left;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lrFirst = true;
|
|
|
|
break;
|
|
|
|
case "right":
|
|
|
|
if (!isNeedAdaptHeight) {
|
|
|
|
var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? extraWidth : extraHeight;
|
|
|
|
if (isRightSpaceEnough(combo, popup, tW)) {
|
|
|
|
left = getRightPosition(combo, popup, tW, container).left;
|
|
|
|
if (topBottom[0] === "bottom") {
|
|
|
|
pos = getTopAlignPosition(combo, popup, tH, needAdaptHeight, container);
|
|
|
|
} else {
|
|
|
|
pos = getBottomAlignPosition(combo, popup, tH, needAdaptHeight, container);
|
|
|
|
}
|
|
|
|
pos.dir = `right,${pos.dir}`;
|
|
|
|
if (tbFirst) {
|
|
|
|
pos.change = "right";
|
|
|
|
}
|
|
|
|
pos.left = left;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lrFirst = true;
|
|
|
|
break;
|
|
|
|
case "top":
|
|
|
|
var tW = lrFirst ? extraHeight : extraWidth, tH = lrFirst ? extraWidth : extraHeight;
|
|
|
|
if (isTopSpaceEnough(combo, popup, tH)) {
|
|
|
|
top = getTopPosition(combo, popup, tH, container).top;
|
|
|
|
if (leftRight[0] === "right") {
|
|
|
|
pos = getLeftAlignPosition(combo, popup, tW, container);
|
|
|
|
} else {
|
|
|
|
pos = getRightAlignPosition(combo, popup, tW, container);
|
|
|
|
}
|
|
|
|
pos.dir = `top,${pos.dir}`;
|
|
|
|
if (lrFirst) {
|
|
|
|
pos.change = "top";
|
|
|
|
}
|
|
|
|
pos.top = top;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
if (needAdaptHeight) {
|
|
|
|
isNeedAdaptHeight = true;
|
|
|
|
}
|
|
|
|
tbFirst = true;
|
|
|
|
break;
|
|
|
|
case "bottom":
|
|
|
|
var tW = lrFirst ? extraHeight : extraWidth, tH = lrFirst ? extraWidth : extraHeight;
|
|
|
|
if (isBottomSpaceEnough(combo, popup, tH)) {
|
|
|
|
top = getBottomPosition(combo, popup, tH, container).top;
|
|
|
|
if (leftRight[0] === "right") {
|
|
|
|
pos = getLeftAlignPosition(combo, popup, tW, container);
|
|
|
|
} else {
|
|
|
|
pos = getRightAlignPosition(combo, popup, tW, container);
|
|
|
|
}
|
|
|
|
pos.dir = `bottom,${pos.dir}`;
|
|
|
|
if (lrFirst) {
|
|
|
|
pos.change = "bottom";
|
|
|
|
}
|
|
|
|
pos.top = top;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
if (needAdaptHeight) {
|
|
|
|
isNeedAdaptHeight = true;
|
|
|
|
}
|
|
|
|
tbFirst = true;
|
|
|
|
break;
|
|
|
|
case "innerLeft":
|
|
|
|
if (!isNeedAdaptHeight) {
|
|
|
|
var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? 0 : extraHeight;
|
|
|
|
if (isInnerLeftSpaceEnough(combo, popup, tW)) {
|
|
|
|
left = getInnerLeftPosition(combo, popup, tW).left;
|
|
|
|
if (topBottom[0] === "bottom") {
|
|
|
|
pos = getTopAlignPosition(combo, popup, tH, needAdaptHeight);
|
|
|
|
} else {
|
|
|
|
pos = getBottomAlignPosition(combo, popup, tH, needAdaptHeight);
|
|
|
|
}
|
|
|
|
pos.dir = `innerLeft,${pos.dir}`;
|
|
|
|
if (tbFirst) {
|
|
|
|
pos.change = "innerLeft";
|
|
|
|
}
|
|
|
|
pos.left = left;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lrFirst = true;
|
|
|
|
break;
|
|
|
|
case "innerRight":
|
|
|
|
if (!isNeedAdaptHeight) {
|
|
|
|
var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? extraWidth : extraHeight;
|
|
|
|
if (isInnerRightSpaceEnough(combo, popup, tW)) {
|
|
|
|
left = getInnerRightPosition(combo, popup, tW).left;
|
|
|
|
if (topBottom[0] === "bottom") {
|
|
|
|
pos = getTopAlignPosition(combo, popup, tH, needAdaptHeight);
|
|
|
|
} else {
|
|
|
|
pos = getBottomAlignPosition(combo, popup, tH, needAdaptHeight);
|
|
|
|
}
|
|
|
|
pos.dir = `innerLeft,${pos.dir}`;
|
|
|
|
if (tbFirst) {
|
|
|
|
pos.change = "innerRight";
|
|
|
|
}
|
|
|
|
pos.left = left;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 此处为四个方向放不下时挑空间最大的方向去放置, 也就是说我设置了弹出方向为"bottom,left",
|
|
|
|
// 最后发现实际弹出方向可能是"top,left",那么此时外界获取popup的方向应该是"top,left"
|
|
|
|
switch (directions[0]) {
|
|
|
|
case "left":
|
|
|
|
case "right":
|
|
|
|
if (isRightSpaceLarger(combo)) {
|
|
|
|
left = getRightAdaptPosition(combo, popup, extraWidth, container).left;
|
|
|
|
firstDir = "right";
|
|
|
|
} else {
|
|
|
|
left = getLeftAdaptPosition(combo, popup, extraWidth, container).left;
|
|
|
|
firstDir = "left";
|
|
|
|
}
|
|
|
|
if (topBottom[0] === "bottom") {
|
|
|
|
pos = getTopAlignPosition(combo, popup, extraHeight, needAdaptHeight);
|
|
|
|
pos.left = left;
|
|
|
|
pos.dir = `${firstDir},${pos.dir}`;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
pos = getBottomAlignPosition(combo, popup, extraHeight, needAdaptHeight);
|
|
|
|
pos.left = left;
|
|
|
|
pos.dir = `${firstDir},${pos.dir}`;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
default :
|
|
|
|
if (isBottomSpaceLarger(combo)) {
|
|
|
|
top = getBottomAdaptPosition(combo, popup, extraHeight, needAdaptHeight, container).top;
|
|
|
|
firstDir = "bottom";
|
|
|
|
} else {
|
|
|
|
top = getTopAdaptPosition(combo, popup, extraHeight, needAdaptHeight, container).top;
|
|
|
|
firstDir = "top";
|
|
|
|
}
|
|
|
|
if (leftRight[0] === "right") {
|
|
|
|
pos = getLeftAlignPosition(combo, popup, extraWidth, container);
|
|
|
|
pos.top = top;
|
|
|
|
pos.dir = `${firstDir},${pos.dir}`;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
pos = getRightAlignPosition(combo, popup, extraWidth, container);
|
|
|
|
pos.top = top;
|
|
|
|
pos.dir = `${firstDir},${pos.dir}`;
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function getComboPosition(combo, popup, extraWidth, extraHeight, needAdaptHeight, directions, offsetStyle, positionRelativeElement) {
|
|
|
|
extraWidth || (extraWidth = 0);
|
|
|
|
extraHeight || (extraHeight = 0);
|
|
|
|
const viewportBounds = document.documentElement.getBoundingClientRect();
|
|
|
|
const maxHeight = Math.min(popup.attr("maxHeight") || viewportBounds.height, viewportBounds.height);
|
|
|
|
popup.resetHeight && popup.resetHeight(maxHeight);
|
|
|
|
const position = getComboPositionByDirections(combo, popup, extraWidth, extraHeight, needAdaptHeight, directions || ["bottom", "top", "right", "left"], positionRelativeElement);
|
|
|
|
switch (offsetStyle) {
|
|
|
|
case "center":
|
|
|
|
if (position.change) {
|
|
|
|
var p = getMiddleAdaptPosition(combo, popup, positionRelativeElement);
|
|
|
|
position.top = p.top;
|
|
|
|
} else {
|
|
|
|
var p = getCenterAdaptPosition(combo, popup, positionRelativeElement);
|
|
|
|
position.left = p.left;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "middle":
|
|
|
|
if (position.change) {
|
|
|
|
var p = getCenterAdaptPosition(combo, popup, positionRelativeElement);
|
|
|
|
position.left = p.left;
|
|
|
|
} else {
|
|
|
|
var p = getMiddleAdaptPosition(combo, popup, positionRelativeElement);
|
|
|
|
position.top = p.top;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (needAdaptHeight === true) {
|
|
|
|
popup.resetHeight && popup.resetHeight(Math.min(viewportBounds.height - position.top - (positionRelativeElement ? positionRelativeElement.getBoundingClientRect().top : 0), maxHeight));
|
|
|
|
}
|
|
|
|
|
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取position:fixed相对定位的元素
|
|
|
|
*/
|
|
|
|
export function getPositionRelativeContainingBlock(element) {
|
|
|
|
if (["html", "body", "#document"].indexOf((element.nodeName || "").toLowerCase()) >= 0) {
|
|
|
|
// $FlowFixMe[incompatible-return]: assume body is always available
|
|
|
|
return element.ownerDocument.body;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isExcept(node) {
|
|
|
|
const _computedStyle = getComputedStyle(node);
|
|
|
|
const transform = _computedStyle.transform;
|
|
|
|
const perspective = _computedStyle.perspective;
|
|
|
|
const filter = _computedStyle.filter;
|
|
|
|
const willChange = _computedStyle["will-change"];
|
|
|
|
|
|
|
|
return [transform, perspective, filter].some(value => value !== "none") || (willChange === "transform");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isExcept(element)) {
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
|
|
|
return getPositionRelativeContainingBlock(element.parentNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取position:fixed相对定位的元素的clientRect
|
|
|
|
*/
|
|
|
|
export function getPositionRelativeContainingBlockRect(element) {
|
|
|
|
const positionRelativeElement = getPositionRelativeContainingBlock(element);
|
|
|
|
const rect = positionRelativeElement.getBoundingClientRect();
|
|
|
|
|
|
|
|
return {
|
|
|
|
...rect.toJSON(),
|
|
|
|
scaleX: rect.width / positionRelativeElement.offsetWidth,
|
|
|
|
scaleY: rect.height / positionRelativeElement.offsetHeight,
|
|
|
|
};
|
|
|
|
}
|