Revert "Attribute view support sticky layout (#9617)"

This reverts commit 433f4d5541.
This commit is contained in:
Vanessa 2023-11-10 09:54:49 +08:00
parent 433f4d5541
commit 72eed4671e
8 changed files with 80 additions and 372 deletions

View file

@ -72,10 +72,6 @@
opacity: 0; opacity: 0;
display: flex; display: flex;
&[draggable=true] {
cursor: grab;
}
svg { svg {
height: 25px; height: 25px;
} }
@ -94,10 +90,6 @@
cursor: pointer; cursor: pointer;
} }
&__body {
float: left;
}
&__row { &__row {
display: flex; display: flex;
border-bottom: 1px solid var(--b3-theme-surface-lighter); border-bottom: 1px solid var(--b3-theme-surface-lighter);
@ -121,10 +113,6 @@
.av__gutters { .av__gutters {
opacity: 1; opacity: 1;
} }
.av__firstcol svg {
opacity: 1;
}
} }
&--select { &--select {
@ -148,23 +136,11 @@
} }
} }
&--add {
.av__firstcol svg {
opacity: 1;
}
&:hover {
background-color: var(--b3-list-icon-hover);
}
}
&--header, &--header,
&--footer { &--footer {
background-color: var(--b3-theme-background); background-color: var(--b3-theme-background);
position: relative;
} }
&--add,
&--footer { &--footer {
display: flex; display: flex;
border-top: 1px solid var(--b3-theme-surface-lighter); border-top: 1px solid var(--b3-theme-surface-lighter);
@ -208,6 +184,27 @@
} }
} }
} }
&--add {
color: var(--b3-theme-on-surface);
padding: 5px 5px 5px 7px;
display: flex;
align-items: center;
transition: background 20ms ease-in 0s;
font-size: 87.5%;
svg {
height: 12px;
width: 12px;
color: var(--b3-theme-on-surface);
margin-right: 5px;
flex-shrink: 0;
}
&:hover {
background-color: var(--b3-list-icon-hover);
}
}
} }
&__cell { &__cell {
@ -237,13 +234,6 @@
border-radius: var(--b3-border-radius); border-radius: var(--b3-border-radius);
} }
&--add {
position: sticky;
left: 25px;
font-size: 87.5%;
padding: 0 0.5em;
}
.block__icon { .block__icon {
position: absolute; position: absolute;
right: 5px; right: 5px;
@ -275,7 +265,6 @@
&__celltext { &__celltext {
overflow: hidden; overflow: hidden;
line-height: normal;
.b3-chip { .b3-chip {
margin: 1px 2px; margin: 1px 2px;
@ -294,14 +283,6 @@
} }
&__firstcol { &__firstcol {
background-color: var(--b3-theme-background);
border-right: 1px solid var(--b3-theme-surface-lighter);
position: sticky;
left: 0;
width: 24px;
z-index: 1;
svg { svg {
color: var(--b3-theme-on-surface); color: var(--b3-theme-on-surface);
height: 33px; height: 33px;
@ -311,6 +292,10 @@
box-sizing: border-box; box-sizing: border-box;
float: left; float: left;
} }
&:hover svg {
opacity: 1;
}
} }
&__widthdrag { &__widthdrag {
@ -395,7 +380,6 @@
.protyle-wysiwyg--select, .protyle-wysiwyg--select,
.protyle-wysiwyg--hl { .protyle-wysiwyg--hl {
.av__row--header, .av__row--header,
.av__firstcol,
.av__row--footer { .av__row--footer {
background-color: transparent; background-color: transparent;
} }

View file

@ -32,7 +32,7 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
if (event.shiftKey) { if (event.shiftKey) {
const rowElement = hasClosestByClassName(event.target, "av__row"); const rowElement = hasClosestByClassName(event.target, "av__row");
if (rowElement && !rowElement.classList.contains("av__row--header")) { if (rowElement && !rowElement.classList.contains("av__row--header")) {
selectRow(rowElement.querySelector(".av__check"), "toggle"); selectRow(rowElement.querySelector(".av__firstcol"), "toggle");
return true; return true;
} }
} }
@ -63,8 +63,8 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
return true; return true;
} }
const gutterElement = hasClosestByClassName(event.target, "av__gutter"); const gutterElement = hasClosestByClassName(event.target, "ariaLabel");
if (gutterElement) { if (gutterElement && gutterElement.parentElement.classList.contains("av__gutters")) {
const rowElement = gutterElement.parentElement.parentElement; const rowElement = gutterElement.parentElement.parentElement;
if (gutterElement.dataset.action === "add") { if (gutterElement.dataset.action === "add") {
const avID = blockElement.getAttribute("data-av-id"); const avID = blockElement.getAttribute("data-av-id");
@ -97,7 +97,7 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
return true; return true;
} }
const checkElement = hasClosestByClassName(event.target, "av__check"); const checkElement = hasClosestByClassName(event.target, "av__firstcol");
if (checkElement) { if (checkElement) {
window.siyuan.menus.menu.remove(); window.siyuan.menus.menu.remove();
selectRow(checkElement, "toggle"); selectRow(checkElement, "toggle");
@ -199,10 +199,10 @@ export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLEle
if (cellElement && !cellElement.parentElement.classList.contains("av__row--header")) { if (cellElement && !cellElement.parentElement.classList.contains("av__row--header")) {
const type = cellElement.parentElement.parentElement.firstElementChild.querySelector(`[data-col-id="${cellElement.getAttribute("data-col-id")}"]`).getAttribute("data-dtype") as TAVCol; const type = cellElement.parentElement.parentElement.firstElementChild.querySelector(`[data-col-id="${cellElement.getAttribute("data-col-id")}"]`).getAttribute("data-dtype") as TAVCol;
if (type === "updated" || type === "created" || (type === "block" && !cellElement.getAttribute("data-detached"))) { if (type === "updated" || type === "created" || (type === "block" && !cellElement.getAttribute("data-detached"))) {
selectRow(cellElement.parentElement.querySelector(".av__check"), "toggle"); selectRow(cellElement.parentElement.querySelector(".av__firstcol"), "toggle");
} else { } else {
cellElement.parentElement.parentElement.querySelectorAll(".av__row--select").forEach(item => { cellElement.parentElement.parentElement.querySelectorAll(".av__row--select").forEach(item => {
item.querySelector(".av__check use").setAttribute("xlink:href", "#iconUncheck"); item.querySelector(".av__firstcol use").setAttribute("xlink:href", "#iconUncheck");
item.classList.remove("av__row--select"); item.classList.remove("av__row--select");
}); });
updateHeader(cellElement.parentElement); updateHeader(cellElement.parentElement);
@ -259,7 +259,7 @@ export const avContextmenu = (protyle: IProtyle, rowElement: HTMLElement, positi
blockElement.querySelectorAll(".av__row--select").forEach(item => { blockElement.querySelectorAll(".av__row--select").forEach(item => {
item.classList.remove("av__row--select"); item.classList.remove("av__row--select");
}); });
blockElement.querySelectorAll(".av__check use").forEach(item => { blockElement.querySelectorAll(".av__firstcol use").forEach(item => {
item.setAttribute("xlink:href", "#iconUncheck"); item.setAttribute("xlink:href", "#iconUncheck");
}); });
} }
@ -269,7 +269,7 @@ export const avContextmenu = (protyle: IProtyle, rowElement: HTMLElement, positi
return true; return true;
} }
rowElement.classList.add("av__row--select"); rowElement.classList.add("av__row--select");
rowElement.querySelector(".av__check use").setAttribute("xlink:href", "#iconCheck"); rowElement.querySelector(".av__firstcol use").setAttribute("xlink:href", "#iconCheck");
const rowIds: string[] = []; const rowIds: string[] = [];
const blockIds: string[] = []; const blockIds: string[] = [];
const rowElements = blockElement.querySelectorAll(".av__row--select:not(.av__row--header)"); const rowElements = blockElement.querySelectorAll(".av__row--select:not(.av__row--header)");

View file

@ -19,7 +19,7 @@ export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyl
if (selectCellElement) { if (selectCellElement) {
if (event.key === "Escape") { if (event.key === "Escape") {
selectCellElement.classList.remove("av__cell--select"); selectCellElement.classList.remove("av__cell--select");
selectRow(selectCellElement.parentElement.querySelector(".av__check"), "select"); selectRow(selectCellElement.parentElement.querySelector(".av__firstcol"), "select");
event.preventDefault(); event.preventDefault();
return true; return true;
} }
@ -100,11 +100,11 @@ export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyl
} }
if (event.key === "Escape") { if (event.key === "Escape") {
event.preventDefault(); event.preventDefault();
selectRow(selectRowElements[0].querySelector(".av__check"), "unselectAll"); selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
return true; return true;
} }
if (event.key === "Enter") { if (event.key === "Enter") {
selectRow(selectRowElements[0].querySelector(".av__check"), "unselectAll"); selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
popTextCell(protyle, [selectRowElements[0].querySelector(".av__cell")]); popTextCell(protyle, [selectRowElements[0].querySelector(".av__cell")]);
event.preventDefault(); event.preventDefault();
return true; return true;
@ -112,9 +112,9 @@ export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyl
// TODO event.shiftKey // TODO event.shiftKey
if (event.key === "ArrowUp") { if (event.key === "ArrowUp") {
const previousRowElement = selectRowElements[0].previousElementSibling; const previousRowElement = selectRowElements[0].previousElementSibling;
selectRow(selectRowElements[0].querySelector(".av__check"), "unselectAll"); selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
if (previousRowElement && !previousRowElement.classList.contains("av__row--header")) { if (previousRowElement && !previousRowElement.classList.contains("av__row--header")) {
selectRow(previousRowElement.querySelector(".av__check"), "select"); selectRow(previousRowElement.querySelector(".av__firstcol"), "select");
cellScrollIntoView(nodeElement, previousRowElement.getBoundingClientRect(), true); cellScrollIntoView(nodeElement, previousRowElement.getBoundingClientRect(), true);
} else { } else {
nodeElement.classList.add("protyle-wysiwyg--select"); nodeElement.classList.add("protyle-wysiwyg--select");
@ -124,9 +124,9 @@ export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyl
} }
if (event.key === "ArrowDown") { if (event.key === "ArrowDown") {
const nextRowElement = selectRowElements[selectRowElements.length - 1].nextElementSibling; const nextRowElement = selectRowElements[selectRowElements.length - 1].nextElementSibling;
selectRow(selectRowElements[0].querySelector(".av__check"), "unselectAll"); selectRow(selectRowElements[0].querySelector(".av__firstcol"), "unselectAll");
if (nextRowElement && !nextRowElement.classList.contains("av__row--add")) { if (nextRowElement && !nextRowElement.classList.contains("av__row--add")) {
selectRow(nextRowElement.querySelector(".av__check"), "select"); selectRow(nextRowElement.querySelector(".av__firstcol"), "select");
cellScrollIntoView(nodeElement, nextRowElement.getBoundingClientRect(), true); cellScrollIntoView(nodeElement, nextRowElement.getBoundingClientRect(), true);
} else { } else {
nodeElement.classList.add("protyle-wysiwyg--select"); nodeElement.classList.add("protyle-wysiwyg--select");
@ -137,3 +137,4 @@ export const avKeydown = (event: KeyboardEvent, nodeElement: HTMLElement, protyl
} }
return false; return false;
}; };

View file

@ -6,7 +6,6 @@ import * as dayjs from "dayjs";
import {unicode2Emoji} from "../../../emoji"; import {unicode2Emoji} from "../../../emoji";
import {focusBlock} from "../../util/selection"; import {focusBlock} from "../../util/selection";
import {isMac} from "../../util/compatibility"; import {isMac} from "../../util/compatibility";
import {stickyScrollY} from "../../scroll/stickyScroll";
export const avRender = (element: Element, protyle: IProtyle, cb?: () => void) => { export const avRender = (element: Element, protyle: IProtyle, cb?: () => void) => {
let avElements: Element[] = []; let avElements: Element[] = [];
@ -41,6 +40,8 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: () => void) =
e.firstElementChild.innerHTML = html; e.firstElementChild.innerHTML = html;
} }
const left = e.querySelector(".av__scroll")?.scrollLeft || 0; const left = e.querySelector(".av__scroll")?.scrollLeft || 0;
const headerTransform = (e.querySelector(".av__row--header") as HTMLElement)?.style.transform;
const footerTransform = (e.querySelector(".av__row--footer") as HTMLElement)?.style.transform;
let selectCellId = ""; let selectCellId = "";
const selectCellElement = e.querySelector(".av__cell--select") as HTMLElement; const selectCellElement = e.querySelector(".av__cell--select") as HTMLElement;
if (selectCellElement) { if (selectCellElement) {
@ -51,7 +52,7 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: () => void) =
}, (response) => { }, (response) => {
const data = response.data.view as IAVTable; const data = response.data.view as IAVTable;
// header // header
let tableHTML = '<div class="av__row av__row--header"><div class="av__firstcol av__check"><svg style="height: 32px"><use xlink:href="#iconUncheck"></use></svg></div>'; let tableHTML = '<div class="av__row av__row--header"><div class="av__firstcol"><svg style="height: 32px"><use xlink:href="#iconUncheck"></use></svg></div>';
let calcHTML = ""; let calcHTML = "";
data.columns.forEach((column: IAVColumn) => { data.columns.forEach((column: IAVColumn) => {
if (column.hidden) { if (column.hidden) {
@ -79,10 +80,10 @@ style="width: ${column.width || "200px"}">${getCalcValue(column) || '<svg><use x
data.rows.forEach((row: IAVRow) => { data.rows.forEach((row: IAVRow) => {
tableHTML += `<div class="av__row" data-id="${row.id}"> tableHTML += `<div class="av__row" data-id="${row.id}">
<div class="av__gutters"> <div class="av__gutters">
<button class="av__gutter ariaLabel" data-action="add" data-position="right" aria-label="${isMac() ? window.siyuan.languages.addBelowAbove : window.siyuan.languages.addBelowAbove.replace("", "Alt+")}"><svg><use xlink:href="#iconAdd"></use></svg></button> <button class="ariaLabel" data-action="add" data-position="right" aria-label="${isMac() ? window.siyuan.languages.addBelowAbove : window.siyuan.languages.addBelowAbove.replace("", "Alt+")}"><svg><use xlink:href="#iconAdd"></use></svg></button>
<button class="av__gutter ariaLabel" draggable="true" data-position="right" aria-label="${window.siyuan.languages.rowTip}"><svg><use xlink:href="#iconDrag"></use></svg></button> <button class="ariaLabel" draggable="true" data-position="right" aria-label="${window.siyuan.languages.rowTip}"><svg><use xlink:href="#iconDrag"></use></svg></button>
</div> </div>
<div class="av__firstcol av__check"><svg><use xlink:href="#iconUncheck"></use></svg></div>`; <div class="av__firstcol"><svg><use xlink:href="#iconUncheck"></use></svg></div>`;
row.cells.forEach((cell, index) => { row.cells.forEach((cell, index) => {
if (data.columns[index].hidden) { if (data.columns[index].hidden) {
return; return;
@ -149,7 +150,7 @@ style="width: ${column.width || "200px"}">${getCalcValue(column) || '<svg><use x
} }
if (["text", "template", "url", "email", "phone", "number", "date", "created", "updated"].includes(cell.valueType)) { if (["text", "template", "url", "email", "phone", "number", "date", "created", "updated"].includes(cell.valueType)) {
if (cell.value && cell.value[cell.valueType as "url"].content) { if (cell.value && cell.value[cell.valueType as "url"].content) {
text += `<span ${cell.valueType !== "number" ? "" : 'style="right:auto; left:5px;"'} data-type="copy" class="b3-tooltips b3-tooltips__n block__icon" aria-label="${window.siyuan.languages.copy}"><svg><use xlink:href="#iconCopy"></use></svg></span>`; text += `<span ${cell.valueType !== "number" ? "" : 'style="right:auto;left:5px"'} data-type="copy" class="b3-tooltips b3-tooltips__n block__icon" aria-label="${window.siyuan.languages.copy}"><svg><use xlink:href="#iconCopy"></use></svg></span>`;
} }
} }
tableHTML += `<div class="av__cell" data-id="${cell.id}" data-col-id="${data.columns[index].id}" tableHTML += `<div class="av__cell" data-id="${cell.id}" data-col-id="${data.columns[index].id}"
@ -195,17 +196,13 @@ ${cell.color ? `color:${cell.color};` : ""}">${text}</div>`;
<div class="av__counter fn__none"></div> <div class="av__counter fn__none"></div>
</div> </div>
<div class="av__scroll"> <div class="av__scroll">
<div class="av__body"> <div style="float: left;">
${tableHTML} ${tableHTML}
<div class="av__row--add"> <div class="av__row--add">
<div class="av__firstcol"> <svg><use xlink:href="#iconAdd"></use></svg>
<svg><use xlink:href="#iconAdd"></use></svg> ${window.siyuan.languages.addAttr}
</div>
<div class="av__cell--add">
${window.siyuan.languages.addAttr}
</div>
</div> </div>
<div class="av__row--footer"><div class="av__firstcol"></div>${calcHTML}</div> <div class="av__row--footer"><div style="width: 24px"></div>${calcHTML}</div>
</div> </div>
</div> </div>
</div>`; </div>`;
@ -215,16 +212,11 @@ ${cell.color ? `color:${cell.color};` : ""}">${text}</div>`;
if (left) { if (left) {
e.querySelector(".av__scroll").scrollLeft = left; e.querySelector(".av__scroll").scrollLeft = left;
} }
const bodyElement = e.querySelector<HTMLElement>(".av__body"); if (headerTransform) {
if (bodyElement) { (e.querySelector(".av__row--header") as HTMLElement).style.transform = headerTransform;
const headerElement = bodyElement.querySelector<HTMLElement>(".av__row--header"); }
const footerElement = bodyElement.querySelector<HTMLElement>(".av__row--footer"); if (footerTransform) {
stickyScrollY( (e.querySelector(".av__row--footer") as HTMLElement).style.transform = footerTransform;
protyle.contentElement,
bodyElement as HTMLElement,
headerElement ? [{element: headerElement}] : [],
footerElement ? [{element: footerElement}] : [],
);
} }
if (selectCellId) { if (selectCellId) {
const newCellElement = e.querySelector(`.av__row[data-id="${selectCellId.split(Constants.ZWSP)[0]}"] .av__cell[data-col-id="${selectCellId.split(Constants.ZWSP)[1]}"]`); const newCellElement = e.querySelector(`.av__row[data-id="${selectCellId.split(Constants.ZWSP)[0]}"] .av__cell[data-col-id="${selectCellId.split(Constants.ZWSP)[1]}"]`);

View file

@ -6,12 +6,12 @@ export const selectRow = (checkElement: Element, type: "toggle" | "select" | "un
const useElement = checkElement.querySelector("use"); const useElement = checkElement.querySelector("use");
if (rowElement.classList.contains("av__row--header") || type === "unselectAll") { if (rowElement.classList.contains("av__row--header") || type === "unselectAll") {
if ("#iconCheck" === useElement.getAttribute("xlink:href")) { if ("#iconCheck" === useElement.getAttribute("xlink:href")) {
rowElement.parentElement.querySelectorAll(".av__check").forEach(item => { rowElement.parentElement.querySelectorAll(".av__firstcol").forEach(item => {
item.querySelector("use").setAttribute("xlink:href", "#iconUncheck"); item.querySelector("use").setAttribute("xlink:href", "#iconUncheck");
item.parentElement.classList.remove("av__row--select"); item.parentElement.classList.remove("av__row--select");
}); });
} else { } else {
rowElement.parentElement.querySelectorAll(".av__check").forEach(item => { rowElement.parentElement.querySelectorAll(".av__firstcol").forEach(item => {
item.querySelector("use").setAttribute("xlink:href", "#iconCheck"); item.querySelector("use").setAttribute("xlink:href", "#iconCheck");
item.parentElement.classList.add("av__row--select"); item.parentElement.classList.add("av__row--select");
}); });

View file

@ -4,7 +4,6 @@ import {fetchPost} from "../../util/fetch";
import {onGet} from "../util/onGet"; import {onGet} from "../util/onGet";
import {isMobile} from "../../util/functions"; import {isMobile} from "../../util/functions";
import {hasClosestBlock, hasClosestByClassName} from "../util/hasClosest"; import {hasClosestBlock, hasClosestByClassName} from "../util/hasClosest";
import {stickyScrollY} from "./stickyScroll";
let getIndexTimeout: number; let getIndexTimeout: number;
export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => { export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => {
@ -26,18 +25,26 @@ export const scrollEvent = (protyle: IProtyle, element: HTMLElement) => {
} }
protyle.wysiwyg.element.querySelectorAll(".av").forEach((item: HTMLElement) => { protyle.wysiwyg.element.querySelectorAll(".av").forEach((item: HTMLElement) => {
const bodyElement = item.querySelector(".av__body") as HTMLElement; if (item.parentElement.classList.contains("protyle-wysiwyg")) {
const headerTop = item.offsetTop + 43;
if (bodyElement) { const headerElement = item.querySelector(".av__row--header") as HTMLElement;
const headerElement = bodyElement.querySelector(".av__row--header") as HTMLElement; if (headerElement) {
const footerElement = bodyElement.querySelector(".av__row--footer") as HTMLElement; if (headerTop < element.scrollTop && headerTop + headerElement.parentElement.clientHeight > element.scrollTop) {
headerElement.style.transform = `translateY(${element.scrollTop - headerTop}px)`;
stickyScrollY( } else {
element, headerElement.style.transform = "";
bodyElement, }
headerElement ? [{element: headerElement}] : [], }
footerElement ? [{element: footerElement}] : [], const footerElement = item.querySelector(".av__row--footer") as HTMLElement;
); if (footerElement) {
const footerBottom = headerTop + footerElement.parentElement.clientHeight;
const scrollBottom = element.scrollTop + element.clientHeight + 5;
if (headerTop + 42 + 36 * 2 < scrollBottom && footerBottom > scrollBottom) {
footerElement.style.transform = `translateY(${scrollBottom - footerBottom}px)`;
} else {
footerElement.style.transform = "";
}
}
} }
}); });

View file

@ -1,276 +0,0 @@
export interface IStickyPositionY {
top: number;
bottom: number;
}
export interface IStickyElementY {
element: HTMLElement;
offset?: number;
}
export interface IStickyContextY extends IStickyElementY {
rect: DOMRect;
base: number;
origin: IStickyPositionY;
current: IStickyPositionY;
target: IStickyPositionY;
style: IStickyPositionY;
}
export const stickyScrollY = (
view: HTMLElement, // 视口元素
container: HTMLElement, // 容器元素
topElements: IStickyElementY[] = [], // 顶部粘性元素
bottomElements: IStickyElementY[] = [], // 底部粘性元素
) => {
if (topElements.length === 0 && bottomElements.length === 0) {
return;
}
const viewRect = view.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
/**
* ---------------
* | view |
* --------------- viewRect.bottom
* ----------- -- containerRect.top
* | container |
* -----------
* ====== OR ======
* -----------
* | container |
* ----------- -- containerRect.bottom
* --------------- viewRect.top
* | view |
* ---------------
*/
if (viewRect.bottom <= containerRect.top || containerRect.bottom <= viewRect.top) {
return;
}
const topContext: IStickyContextY[] = topElements.map(item => {
const rect = item.element.getBoundingClientRect();
const base = Number.parseFloat(item.element.style.top) || 0;
item.offset ??= 0;
return {
...item,
rect,
base,
origin: {
top: rect.top - base,
bottom: rect.bottom - base,
},
current: {
top: rect.top,
bottom: rect.bottom,
},
target: {
top: null,
bottom: null,
},
style: {
top: null,
bottom: null,
}
};
});
const bottomContext: IStickyContextY[] = bottomElements.map(item => {
const rect = item.element.getBoundingClientRect();
const base = Number.parseFloat(item.element.style.bottom) || 0;
item.offset ??= 0;
return {
...item,
rect,
base,
origin: {
top: rect.top + base,
bottom: rect.bottom + base,
},
current: {
top: rect.top,
bottom: rect.bottom,
},
target: {
top: null,
bottom: null,
},
style: {
top: null,
bottom: null,
}
};
});
let handleTop = false;
let handleBottom = false;
switch (true) {
/**
* --------------- viewRect.top
* | |
* | view |
* | ----------- | containerRect.top
* ------------- viewRect.bottom
* | container |
* ----------- -- containerRect.bottom
*/
case viewRect.top <= containerRect.top
&& containerRect.top <= viewRect.bottom
&& viewRect.top <= viewRect.bottom:
handleBottom = true;
break;
/**
* --------------- viewRect.top
* | view |
* | ----------- | containerRect.top
* | | container | |
* | ----------- | containerRect.bottom
* --------------- viewRect.bottom
*/
case viewRect.top <= containerRect.top
&& containerRect.bottom <= viewRect.bottom:
break;
/**
* ----------- -- containerRect.top
* ------------- viewRect.top
* | | | |} view
* ------------- viewRect.bottom
* | container |
* ----------- -- containerRect.bottom
*/
case containerRect.top <= viewRect.top
&& viewRect.bottom <= containerRect.bottom:
handleTop = true;
handleBottom = true;
break;
/**
* ----------- -- containerRect.top
* | container |
* ------------- viewRect.top
* | ----------- | containerRect.bottom
* | view |
* -|-----------|- viewRect.bottom
*/
case containerRect.top <= viewRect.top
&& viewRect.top <= containerRect.bottom
&& containerRect.bottom <= viewRect.bottom:
handleTop = true;
break;
default:
break;
}
if (handleTop) {
if (topContext.length > 0) {
topContext.reduceRight((next, current) => {
switch (true) {
/**
* ----------- -- containerRect.top
* ------------- viewRect.top
* | | | | current.target.top - current.offset
* | | | | current.origin.top
* | | | | current.origin.bottom
* | | | | next.origin.top
* | | | | next.origin.bottom
* ------------- viewRect.bottom
* ----------- -- containerRect.bottom
*/
case viewRect.top <= (current.origin.top - current.offset):
current.target.top = current.origin.top;
current.target.bottom = current.origin.bottom;
current.style.top = null;
break;
/**
* ----------- -- containerRect.top
* | | -- current.origin.top
* | | -- current.origin.bottom
* ------------- viewRect.top
* | | ------- | | current.target.top
* | | ------- | | current.target.bottom
* ------------- viewRect.bottom
* | container |
* ----------- -- containerRect.bottom
*/
default:
current.target.top = viewRect.top + current.offset;
current.target.bottom = current.target.top + current.rect.height;
if (next) {
const nextTop = Math.min(next.target.top, next.origin.top);
if (nextTop < current.target.bottom) {
const diff = nextTop - current.target.bottom;
current.target.top += diff;
current.target.bottom += diff;
}
}
current.style.top = current.base + (current.target.top - current.current.top);
break;
}
return current;
}, null);
}
}
if (handleBottom) {
if (bottomContext.length > 0) {
bottomContext.reduce((last, current) => {
switch (true) {
/**
* ----------- -- containerRect.top
* ------------- viewRect.top
* | | | | last.origin.top
* | | | | last.origin.bottom
* | | | | current.origin.top
* | | | | current.origin.bottom
* | | | | current.target.bottom + current.offset
* ------------- viewRect.bottom
* ----------- -- containerRect.bottom
*/
case (current.origin.bottom + current.offset) <= viewRect.bottom:
current.target.top = current.origin.top;
current.target.bottom = current.origin.bottom;
current.style.bottom = null;
break;
/**
* ----------- -- containerRect.top
* ------------- viewRect.top
* | | ------- | | current.target.top
* | | ------- | | current.target.bottom
* ------------- viewRect.bottom
* | | -- current.origin.top
* | | -- current.origin.bottom
* | container |
* ----------- -- containerRect.bottom
*/
default:
current.target.bottom = viewRect.bottom - current.offset;
current.target.top = current.target.bottom - current.rect.height;
if (last) {
const lastBottom = Math.max(last.target.bottom, last.origin.bottom);
if (current.target.top < lastBottom) {
const diff = lastBottom - current.target.top;
current.target.top += diff;
current.target.bottom += diff;
}
}
current.style.bottom = current.base - (current.target.bottom - current.current.bottom);
break;
}
return current;
}, null);
}
}
[...topContext, ...bottomContext].forEach(item => {
item.element.style.top = item.style.top ? `${item.style.top}px` : null;
item.element.style.bottom = item.style.bottom ? `${item.style.bottom}px` : null;
});
}

View file

@ -189,7 +189,7 @@ export class WYSIWYG {
protyle.wysiwyg.element.querySelectorAll(".img--select, .av__cell--select, .av__row--select").forEach((item: HTMLElement) => { protyle.wysiwyg.element.querySelectorAll(".img--select, .av__cell--select, .av__row--select").forEach((item: HTMLElement) => {
if (item.classList.contains("av__row--select") && !hasClosestByClassName(element, "av")) { if (item.classList.contains("av__row--select") && !hasClosestByClassName(element, "av")) {
item.classList.remove("av__row--select"); item.classList.remove("av__row--select");
item.querySelector(".av__check use").setAttribute("xlink:href", "#iconUncheck"); item.querySelector(".av__firstcol use").setAttribute("xlink:href", "#iconUncheck");
updateHeader(item); updateHeader(item);
} else { } else {
item.classList.remove("img--select", "av__cell--select"); item.classList.remove("img--select", "av__cell--select");