length: getElementLength()

in dotcom-rendering/src/lib/find-adslots.amp.ts [51:159]


			length: getElementLength(e),
		};
	});
};

const getLengthOfFollowingTextElements = (
	elements: ElementWithLength[],
): number => {
	const firstNonTextIndex = elements.findIndex(
		(e) => !isTextElement(e.element),
	);

	return elements
		.slice(0, firstNonTextIndex)
		.map((e) => e.length)
		.reduce((a, b) => a + b, 0);
};

const suitableAdNeighbour = (e: ElementWithLength): boolean => {
	return isTextElement(e.element) && e.length > SMALL_PARA_CHARS;
};

const hasForwardBuffer = (
	elements: ElementWithLength[],
	index: number,
): boolean => {
	const forwardElements = elements.slice(index + 1, elements.length);
	const meetsThreshold =
		getLengthOfFollowingTextElements(forwardElements) >=
		NONTEXT_BUFFER_FORWARD;
	const noForwardsEmbeds =
		forwardElements.filter((e) => isTextElement(e.element)).length ===
		forwardElements.length;

	const enoughCharsForward = meetsThreshold || noForwardsEmbeds;

	const neighbour = elements[index];

	const neighbourSuitable = neighbour
		? suitableAdNeighbour(neighbour)
		: false;
	return enoughCharsForward && neighbourSuitable;
};

const hasBackwardBuffer = (
	elements: ElementWithLength[],
	index: number,
): boolean => {
	const backwardsElements = elements.slice(0, index).reverse();
	const meetsThreshold =
		getLengthOfFollowingTextElements(backwardsElements) >=
		NONTEXT_BUFFER_BACKWARD;
	const noBackwardsEmbeds =
		backwardsElements.filter((e) => isTextElement(e.element)).length ===
		backwardsElements.length;

	const enoughCharsBackward = meetsThreshold || noBackwardsEmbeds;

	const neighbour = elements[index];

	return !!neighbour && suitableAdNeighbour(neighbour) && enoughCharsBackward;
};

/**
 * There are some magic numbers here - obtained by eyeballing content. Feel free
 * to update them if you notice issues.
 */
const sufficientSpaceSinceLastAd = (
	charsSinceLastAd: number,
	paragraphsSinceLastAd: number,
): boolean => {
	return (
		(charsSinceLastAd > 700 && paragraphsSinceLastAd > 1) ||
		charsSinceLastAd > 900
	);
};

const hasSpaceForAd = (
	elements: ElementWithLength[],
	index: number,
	charsSinceLastAd: number,
	paragraphsSinceLastAd: number,
): boolean => {
	return (
		sufficientSpaceSinceLastAd(charsSinceLastAd, paragraphsSinceLastAd) &&
		hasBackwardBuffer(elements, index) &&
		hasForwardBuffer(elements, index)
	);
};

// Returns index of items to place ads *after*
export const findAdSlots = (elements: FEElement[]): number[] => {
	let charsSinceLastAd = 0;
	let paragraphsSinceLastAd = 0;
	let adCount = 0;
	const adSlots = [];

	const elementsWithLength = getElementsWithLength(elements);

	for (let i = 0; i < elementsWithLength.length; i += 1) {
		const currentElement = elements[i];
		const currentElementWithLength = elementsWithLength[i];

		if (
			currentElement &&
			currentElementWithLength &&
			adCount < AD_LIMIT &&
			isTextElement(currentElement)
		) {