resolveVerticalDirection

This commit is contained in:
Niels Lyngsø
2024-02-15 10:20:37 +01:00
parent b6f0cb9681
commit 7b6c6db9b0

View File

@@ -7,6 +7,48 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import '../block-grid-entry/index.js';
import { UmbSorterController, type UmbSorterConfig } from '@umbraco-cms/backoffice/sorter';
// Utils:
// TODO: Maybe move these into their own files..
function getInterpolatedIndexOfPositionInWeightMap(target: number, weights: Array<number>) {
const map = [0];
weights.reduce((a, b, i) => {
return (map[i + 1] = a + b);
}, 0);
const foundValue = map.reduce((a, b) => {
const aDiff = Math.abs(a - target);
const bDiff = Math.abs(b - target);
if (aDiff === bDiff) {
return a < b ? a : b;
} else {
return bDiff < aDiff ? b : a;
}
});
const foundIndex = map.indexOf(foundValue);
const targetDiff = target - foundValue;
let interpolatedIndex = foundIndex;
if (targetDiff < 0 && foundIndex === 0) {
// Don't adjust.
} else if (targetDiff > 0 && foundIndex === map.length - 1) {
// Don't adjust.
} else {
const foundInterpolationWeight = weights[targetDiff >= 0 ? foundIndex : foundIndex - 1];
interpolatedIndex += foundInterpolationWeight === 0 ? interpolatedIndex : targetDiff / foundInterpolationWeight;
}
return interpolatedIndex;
}
function getAccumulatedValueOfIndex(index: number, weights: Array<number>) {
const len = Math.min(index, weights.length);
let i = 0,
calc = 0;
while (i < len) {
calc += weights[i++];
}
return calc;
}
const SORTER_CONFIG: UmbSorterConfig<UmbBlockGridLayoutModel, UmbBlockGridEntryElement> = {
getUniqueOfElement: (element) => {
return element.contentUdi!;
@@ -14,12 +56,128 @@ const SORTER_CONFIG: UmbSorterConfig<UmbBlockGridLayoutModel, UmbBlockGridEntryE
getUniqueOfModel: (modelEntry) => {
return modelEntry.contentUdi;
},
resolveVerticalDirection: (args) => {
/** We need some data about the grid to figure out if there is room to be placed next to the found element */
const approvedContainerComputedStyles = getComputedStyle(args.containerElement);
const gridColumnGap = Number(approvedContainerComputedStyles.columnGap.split('px')[0]) || 0;
const gridColumnNumber = parseInt(
approvedContainerComputedStyles.getPropertyValue('--umb-block-grid--grid-columns'),
10,
);
const foundElColumns = parseInt(args.relatedElement.dataset.colSpan ?? '', 10);
const currentElementColumns = args.item.columnSpan;
if (currentElementColumns >= gridColumnNumber) {
return true;
}
// Get grid template:
const approvedContainerGridColumns = approvedContainerComputedStyles.gridTemplateColumns
.trim()
.split('px')
.map((x) => Number(x))
.filter((n) => n > 0)
.map((n, i, list) => (list.length === i ? n : n + gridColumnGap));
// ensure all columns are there.
// This will also ensure handling non-css-grid mode,
// use container width divided by amount of columns( or the item width divided by its amount of columnSpan)
let amountOfColumnsInWeightMap = approvedContainerGridColumns.length;
const amountOfUnknownColumns = gridColumnNumber - amountOfColumnsInWeightMap;
if (amountOfUnknownColumns > 0) {
const accumulatedValue =
getAccumulatedValueOfIndex(amountOfColumnsInWeightMap, approvedContainerGridColumns) || 0;
const missingColumnWidth = (args.containerRect.width - accumulatedValue) / amountOfUnknownColumns;
if (missingColumnWidth > 0) {
while (amountOfColumnsInWeightMap++ < gridColumnNumber) {
approvedContainerGridColumns.push(missingColumnWidth);
}
}
}
let offsetPlacement = 0;
/* If placeholder is in this same line, we want to assume that it will offset the placement of the found element,
which provides more potential space for the item to drop at.
This is relevant in this calculation where we look at the space to determine if its a vertical or horizontal drop in relation to the found element.
*/
if (args.placeholderIsInThisRow && args.elementRect.left < args.relatedRect.left) {
offsetPlacement = -(args.elementRect.width + gridColumnGap);
}
const relatedStartX = Math.max(args.relatedRect.left - args.containerRect.left + offsetPlacement, 0);
const relatedStartCol = Math.round(
getInterpolatedIndexOfPositionInWeightMap(relatedStartX, approvedContainerGridColumns),
);
// If the found related element does not have enough room after which for the current element, then we go vertical mode:
return (
relatedStartCol + (args.horizontalPlaceAfter ? foundElColumns : 0) + currentElementColumns > gridColumnNumber
);
},
identifier: 'block-grid-editor',
itemSelector: 'umb-block-grid-entry',
//ignorerSelector: '', // No ignorerSelector, as we want to ignore nothing.
containerSelector: '.umb-block-grid__layout-container',
};
function resolveVerticalDirection(data) {
/** We need some data about the grid to figure out if there is room to be placed next to the found element */
const approvedContainerComputedStyles = getComputedStyle(data.containerElement);
const gridColumnGap = Number(approvedContainerComputedStyles.columnGap.split('px')[0]) || 0;
const gridColumnNumber = parseInt(
approvedContainerComputedStyles.getPropertyValue('--umb-block-grid--grid-columns'),
10,
);
const foundElColumns = parseInt(data.relatedElement.dataset.colSpan, 10);
const currentElementColumns = data.item.columnSpan;
if (currentElementColumns >= gridColumnNumber) {
return true;
}
// Get grid template:
const approvedContainerGridColumns = approvedContainerComputedStyles.gridTemplateColumns
.trim()
.split('px')
.map((x) => Number(x))
.filter((n) => n > 0)
.map((n, i, list) => (list.length === i ? n : n + gridColumnGap));
// ensure all columns are there.
// This will also ensure handling non-css-grid mode,
// use container width divided by amount of columns( or the item width divided by its amount of columnSpan)
let amountOfColumnsInWeightMap = approvedContainerGridColumns.length;
const amountOfUnknownColumns = gridColumnNumber - amountOfColumnsInWeightMap;
if (amountOfUnknownColumns > 0) {
let accumulatedValue = getAccumulatedValueOfIndex(amountOfColumnsInWeightMap, approvedContainerGridColumns) || 0;
const layoutWidth = data.containerRect.width;
const missingColumnWidth = (layoutWidth - accumulatedValue) / amountOfUnknownColumns;
if (missingColumnWidth > 0) {
while (amountOfColumnsInWeightMap++ < gridColumnNumber) {
approvedContainerGridColumns.push(missingColumnWidth);
}
}
}
let offsetPlacement = 0;
/* If placeholder is in this same line, we want to assume that it will offset the placement of the found element,
which provides more potential space for the item to drop at.
This is relevant in this calculation where we look at the space to determine if its a vertical or horizontal drop in relation to the found element.
*/
if (data.placeholderIsInThisRow && data.elementRect.left < data.relatedRect.left) {
offsetPlacement = -(data.elementRect.width + gridColumnGap);
}
const relatedStartX = Math.max(data.relatedRect.left - data.containerRect.left + offsetPlacement, 0);
const relatedStartCol = Math.round(
getInterpolatedIndexOfPositionInWeightMap(relatedStartX, approvedContainerGridColumns),
);
// If the found related element does not have enough room after which for the current element, then we go vertical mode:
return relatedStartCol + (data.horizontalPlaceAfter ? foundElColumns : 0) + currentElementColumns > gridColumnNumber;
}
/**
* @element umb-block-grid-entries
*/