* Add the preview card to logged out feed initial content * initialise the initial dropdowns added on the logged out feed * minor tweak to selector * flip the follow button and the summary * add minimal preview card to build article HTML * WIP: data fetched an inserted into card on logged out feed * WIP: cards added to logged in feed * create separate profile preview card component * small style tweak, import pack on each page that shows feed cards * rename * tweak some styling issues * make sure follow buttons init in cards * populate all matching metadata placeholders after fetch * don't render full preview card upfront on logged out feed * refactors from PR comments * fix issue in person search results * remove check for article author link that will be superseded by cypress test for preview card * Revert "remove check for article author link that will be superseded by cypress test for preview card" This reverts commit 9b42804ffd0f051891c87293d0b791ed2bb0367f. * Revert "fix issue in person search results" This reverts commit 04941e3520c0895212141193b60f2933faed5ca1. * only show the preview cards on story cards for Posts (not users etc in search results) * correct display on collections view * remove link check that will be replaced by cypress test * tweaks to small issues, add a test for the logged out feed * add tests for logged in home feed, logged out tag index * add search test and tag index logged in test * fixes to preview profile spec * tweak to followauthor spec * add cypress test for preview on series page * use a unique test user for series test * correct the jsdoc comments * tweaks following PR review * allow feed preview cards to reposition * move to separate file from pack
115 lines
3.5 KiB
JavaScript
115 lines
3.5 KiB
JavaScript
import { h, render } from 'preact';
|
|
import { UserMetadata } from '../profilePreviewCards/UserMetadata';
|
|
import {
|
|
initializeDropdown,
|
|
getDropdownRepositionListener,
|
|
} from '@utilities/dropdownUtils';
|
|
import { request } from '@utilities/http/request';
|
|
|
|
const cachedAuthorMetadata = {};
|
|
|
|
async function populateMissingMetadata(metadataPlaceholder) {
|
|
const { authorId, fetched } = metadataPlaceholder.dataset;
|
|
|
|
// If the metadata is already being fetched, do nothing
|
|
if (fetched) {
|
|
return;
|
|
}
|
|
metadataPlaceholder.dataset.fetched = 'true';
|
|
|
|
const previouslyFetchedAuthorMetadata = cachedAuthorMetadata[authorId];
|
|
|
|
if (previouslyFetchedAuthorMetadata) {
|
|
renderMetadata(previouslyFetchedAuthorMetadata, metadataPlaceholder);
|
|
} else {
|
|
const response = await request(`/profile_preview_cards/${authorId}`);
|
|
const authorMetadata = await response.json();
|
|
|
|
cachedAuthorMetadata[authorId] = authorMetadata;
|
|
renderMetadata(authorMetadata, metadataPlaceholder);
|
|
}
|
|
}
|
|
|
|
function renderMetadata(metadata, placeholder) {
|
|
const container = placeholder.parentElement;
|
|
|
|
render(<UserMetadata {...metadata} />, container, placeholder);
|
|
|
|
container
|
|
.closest('.profile-preview-card__content')
|
|
.style.setProperty('--card-color', metadata.card_color);
|
|
}
|
|
|
|
function checkForPreviewCardDetails(event) {
|
|
const { target } = event;
|
|
|
|
if (target.classList.contains('profile-preview-card__trigger')) {
|
|
const metadataPlaceholder = target.parentElement.getElementsByClassName(
|
|
'author-preview-metadata-container',
|
|
)[0];
|
|
|
|
if (metadataPlaceholder) {
|
|
// User is within one of the story cards - and the metadata has not been fetched yet
|
|
populateMissingMetadata(metadataPlaceholder);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function listenForHoveredOrFocusedStoryCards() {
|
|
const mainContent = document.getElementById('main-content');
|
|
|
|
mainContent.addEventListener('mouseover', checkForPreviewCardDetails);
|
|
mainContent.addEventListener('focusin', checkForPreviewCardDetails);
|
|
}
|
|
|
|
export function initializeFeedPreviewCards() {
|
|
// Select all preview card triggers that haven't already been initialized
|
|
const allPreviewCardTriggers = document.querySelectorAll(
|
|
'button[id^=story-author-preview-trigger]:not([data-initialized])',
|
|
);
|
|
|
|
for (const previewTrigger of allPreviewCardTriggers) {
|
|
const dropdownContentId = previewTrigger.getAttribute('aria-controls');
|
|
const dropdownElement = document.getElementById(dropdownContentId);
|
|
|
|
if (dropdownElement) {
|
|
initializeDropdown({
|
|
triggerElementId: previewTrigger.id,
|
|
dropdownContentId,
|
|
onOpen: () => dropdownElement?.classList.add('showing'),
|
|
onClose: () => dropdownElement?.classList.remove('showing'),
|
|
});
|
|
|
|
previewTrigger.dataset.initialized = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
const observer = new MutationObserver((mutationsList) => {
|
|
mutationsList.forEach((mutation) => {
|
|
if (mutation.type === 'childList') {
|
|
initializeFeedPreviewCards();
|
|
}
|
|
});
|
|
});
|
|
|
|
if (document.getElementById('index-container')) {
|
|
observer.observe(document.getElementById('index-container'), {
|
|
childList: true,
|
|
subtree: true,
|
|
});
|
|
}
|
|
|
|
// Preview card dropdowns reposition on scroll
|
|
const dropdownRepositionListener = getDropdownRepositionListener();
|
|
document.addEventListener('scroll', dropdownRepositionListener);
|
|
|
|
InstantClick.on('change', () => {
|
|
observer.disconnect();
|
|
document.removeEventListener('scroll', dropdownRepositionListener);
|
|
});
|
|
|
|
window.addEventListener('beforeunload', () => {
|
|
observer.disconnect();
|
|
document.removeEventListener('scroll', dropdownRepositionListener);
|
|
});
|