Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wire item tiles are not uniform in size for some searches #734

Merged
merged 4 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
'@typescript-eslint',
],
'rules': {
'react/prop-types': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/ban-ts-comment': 0,
'indent': [
Expand Down
92 changes: 85 additions & 7 deletions assets/agenda/components/AgendaListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
getInternalNote,
} from '../utils';
import ActionMenu from '../../components/ActionMenu';
import {LIST_ANIMATIONS, isMobilePhone} from 'utils';
import {LIST_ANIMATIONS, isMobilePhone, gettext} from 'utils';

interface IProps {
item: IAgendaItem;
Expand All @@ -44,6 +44,11 @@
resetActioningItem(): void;
}

const isHTML = (value: string) => {
const doc = new DOMParser().parseFromString(value, 'text/html');
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
};

class AgendaListItem extends React.Component<IProps> {
dom: {article: HTMLElement | null};

Expand Down Expand Up @@ -172,6 +177,59 @@
};
}

getSearchSegments(_description: string) {
const domWithoutHighlightedText = new DOMParser().parseFromString(_description, 'text/html');
domWithoutHighlightedText.querySelectorAll('span.es-highlight').forEach((element) => {
element.remove();
});

const description = isHTML(domWithoutHighlightedText.body.outerHTML) ? _description : _description.split('\n').map((p) => `<p>${p}</p>`).join('');

const dom = new DOMParser().parseFromString(description.replace(/\n/g, '<br />'), 'text/html');
const arrayOfParagraphs = dom.body.querySelectorAll('p');
const numberOfResults = dom.body.querySelectorAll('span.es-highlight').length;

const getSegmentCount = (p: HTMLParagraphElement): number => {
// adding one because if there are 2 <br> tags it means there are 3 segments
return p.getElementsByTagName('br').length + 1;
};

const descriptionHTMLArr: HTMLParagraphElement[] = [];
let segmentsRemainingToBeAdded = 3;
let paragraphsInnerText = '';

arrayOfParagraphs.forEach((paragraph, i) => {
const span = paragraph.getElementsByClassName('es-highlight');

if (span.length > 0) {
[...arrayOfParagraphs].slice(i, arrayOfParagraphs.length).forEach((paragraph, i) => {

Check warning on line 205 in assets/agenda/components/AgendaListItem.tsx

View workflow job for this annotation

GitHub Actions / client

'i' is defined but never used
if (segmentsRemainingToBeAdded > 0) {
paragraphsInnerText += paragraph.innerText;
paragraph.innerHTML = paragraph.innerHTML.split('<br>').filter((p: string) => p.trim() !== '').slice(0, segmentsRemainingToBeAdded).join('<br>');

segmentsRemainingToBeAdded = segmentsRemainingToBeAdded - getSegmentCount(paragraph);

descriptionHTMLArr.push(paragraph);
}
});
}
});

let numberOfRenderResults = 0;
descriptionHTMLArr.forEach(element => {
numberOfRenderResults += element.querySelectorAll('span.es-highlight').length;
});

return {
/**
* keep in mind that first 3 segments might be 1-3 paragraphs
*/
firstThreeSearchSegments: descriptionHTMLArr,
hasMoreSearchContent: dom.body.innerText.length > paragraphsInnerText.length,
numberOfNotRenderResults: numberOfResults - numberOfRenderResults,
};
}

renderListItem(isMobile: boolean, children: React.ReactNode) {
const {item, isExtended, group, planningId, listConfig} = this.props;
const classes = this.getClassNames(isExtended);
Expand All @@ -180,15 +238,35 @@
// Show headline for adhoc planning items
const showHeadline = item.event == null && (item.headline?.length ?? 0) > 0;
const {firstThreeSegments, hasMoreContent} = this.getSegments(description);
const {firstThreeSearchSegments, hasMoreSearchContent, numberOfNotRenderResults} = this.getSearchSegments(description);

const renderDescription = (() => {
const isHTML = (value: string) => {
const doc = new DOMParser().parseFromString(value, 'text/html');
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
};

if (item.es_highlight != null && (item.es_highlight.definition_short ?? '').length > 0) {
return <div style={{whiteSpace: 'pre-line'}} dangerouslySetInnerHTML={{__html: description}} />;
return (
firstThreeSearchSegments.map((paragraph, i: number) => {
const lastChild: boolean = firstThreeSearchSegments.length - 1 === i;
const showThreeDots = lastChild && hasMoreSearchContent;

const Wrapper: React.ComponentType<{children: React.ReactNode}> = ({children}) => {
if (lastChild && numberOfNotRenderResults > 0) {
return (
<div key={i} className='d-flex gap-1 align-items-end'>
{children}
<span className='wire-articles__item__text--muted'>({gettext('{{n}} more', {n: numberOfNotRenderResults})})</span>
</div>
);
} else {
return <>{children}</>;
}
};

return (
<Wrapper key={i}>
<div className={showThreeDots ? 'wire-articles__item__text--last-child' : ''} dangerouslySetInnerHTML={{__html: paragraph.outerHTML}} />
</Wrapper>
);
})
);
} else {
if (isHTML(description)) {
return (
Expand Down
5 changes: 4 additions & 1 deletion assets/styles/article-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,9 @@
&--headline {
margin-inline-start: var(--space--2);
}
&--muted {
color: var(--color-text--muted);
}
}
.wire-articles__item__versions-btn {
margin-inline-start: 24px;
Expand Down Expand Up @@ -987,4 +990,4 @@ a.wire-articles__versions {
border-block-end: calc(var(--multiday-label-height) / 2) solid transparent;
}
}
}
}
Loading