initial commit

This commit is contained in:
2021-12-10 12:03:04 +00:00
commit c46c7ddbf0
3643 changed files with 582794 additions and 0 deletions

View File

@ -0,0 +1,40 @@
/**
* External dependencies
*/
import { RawHTML, useMemo } from '@wordpress/element';
import { WordCountType } from '@woocommerce/block-settings';
/**
* Internal dependencies
*/
import { generateSummary } from './utils';
interface SummaryProps {
className?: string;
source: string;
maxLength?: number;
countType?: WordCountType;
}
/**
* Summary component.
*
* @param {Object} props Component props.
* @param {string} props.source Source text.
* @param {number} props.maxLength Max length of the summary, using countType.
* @param {string} props.countType One of words, characters_excluding_spaces, or characters_including_spaces.
* @param {string} props.className Class name for rendered component.
*/
export const Summary = ( {
source,
maxLength = 15,
countType = 'words',
className = '',
}: SummaryProps ): JSX.Element => {
const summaryText = useMemo( () => {
return generateSummary( source, maxLength, countType );
}, [ source, maxLength, countType ] );
return <RawHTML className={ className }>{ summaryText }</RawHTML>;
};
export default Summary;

View File

@ -0,0 +1,109 @@
/**
* Internal dependencies
*/
import { generateSummary } from '../utils';
describe( 'Summary Component', () => {
describe( 'Test the generateSummary utility', () => {
const testContent =
'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p><p>Ut enim ad minim veniam, quis <strong>nostrud</strong> exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p><p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>';
it( 'Default', async () => {
const result = generateSummary( testContent );
expect( result.trim() ).toEqual(
'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore&hellip;</p>'
);
} );
it( 'No max words - return full description', async () => {
const result = generateSummary( testContent, 100000 );
expect( result.trim() ).toEqual(
'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>\n<p>Ut enim ad minim veniam, quis <strong>nostrud</strong> exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>\n<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>\n<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>'
);
} );
it( 'Limit to 3 words', async () => {
const result = generateSummary( testContent, 3 );
expect( result.trim() ).toEqual(
'<p>Lorem ipsum dolor&hellip;</p>'
);
} );
it( 'Limit to 1 word', async () => {
const result = generateSummary( testContent, 1 );
expect( result.trim() ).toEqual( '<p>Lorem&hellip;</p>' );
} );
it( 'Limit to 15 characters, including spaces.', async () => {
const result = generateSummary(
testContent,
15,
'characters_including_spaces'
);
expect( result.trim() ).toEqual( '<p>Lorem ipsum dol&hellip;</p>' );
} );
it( 'Limit to 15 characters, excluding spaces.', async () => {
const result = generateSummary(
testContent,
15,
'characters_excluding_spaces'
);
expect( result.trim() ).toEqual(
'<p>Lorem ipsum dolor&hellip;</p>'
);
} );
} );
describe( 'Test the generateSummary utility with HTML tags in strings', () => {
const testContent =
'<p>Lorem <strong class="classname">ipsum</strong> dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.</p>';
it( 'Limit string to 10 characters', async () => {
const result = generateSummary(
testContent,
10,
'characters_excluding_spaces'
);
expect( result.trim() ).toEqual( '<p>Lorem ipsum&hellip;</p>' );
} );
it( 'Limit string to 5 words', async () => {
const result = generateSummary( testContent, 5, 'words' );
expect( result.trim() ).toEqual(
'<p>Lorem ipsum dolor sit amet&hellip;</p>'
);
} );
it( 'First paragraph only - tags are not stripped.', async () => {
const result = generateSummary( testContent, 9999, 'words' );
expect( result.trim() ).toEqual(
'<p>Lorem <strong class="classname">ipsum</strong> dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.</p>'
);
} );
} );
describe( 'Test the generateSummary utility with special chars', () => {
const testContent =
'<p>我不知道这是否行得通。</p><p>我是用中文写的说明,因此我们可以测试如何修剪产品摘要中的单词。</p>';
it( 'Default', async () => {
const result = generateSummary(
testContent,
15,
'characters_excluding_spaces'
);
expect( result.trim() ).toEqual( '<p>我不知道这是否行得通。</p>' );
} );
it( 'Limit to 3 words', async () => {
const result = generateSummary(
testContent,
3,
'characters_excluding_spaces'
);
expect( result.trim() ).toEqual( '<p>我不知&hellip;</p>' );
} );
} );
} );

View File

@ -0,0 +1,131 @@
/**
* External dependencies
*/
import { count } from '@wordpress/wordcount';
import { autop } from '@wordpress/autop';
/**
* Generates the summary text from a string of text.
*
* @param {string} source Source text.
* @param {number} maxLength Limit number of countType returned if text has multiple paragraphs.
* @param {string} countType What is being counted. One of words, characters_excluding_spaces, or characters_including_spaces.
* @return {string} Generated summary.
*/
export const generateSummary = (
source,
maxLength = 15,
countType = 'words'
) => {
const sourceWithParagraphs = autop( source );
const sourceWordCount = count( sourceWithParagraphs, countType );
if ( sourceWordCount <= maxLength ) {
return sourceWithParagraphs;
}
const firstParagraph = getFirstParagraph( sourceWithParagraphs );
const firstParagraphWordCount = count( firstParagraph, countType );
if ( firstParagraphWordCount <= maxLength ) {
return firstParagraph;
}
if ( countType === 'words' ) {
return trimWords( firstParagraph, maxLength );
}
return trimCharacters(
firstParagraph,
maxLength,
countType === 'characters_including_spaces'
);
};
/**
* Get first paragraph from some HTML text, or return whole string.
*
* @param {string} source Source text.
* @return {string} First paragraph found in string.
*/
const getFirstParagraph = ( source ) => {
const pIndex = source.indexOf( '</p>' );
if ( pIndex === -1 ) {
return source;
}
return source.substr( 0, pIndex + 4 );
};
/**
* Remove HTML tags from a string.
*
* @param {string} htmlString String to remove tags from.
* @return {string} Plain text string.
*/
const removeTags = ( htmlString ) => {
const tagsRegExp = /<\/?[a-z][^>]*?>/gi;
return htmlString.replace( tagsRegExp, '' );
};
/**
* Remove trailing punctuation and append some characters to a string.
*
* @param {string} text Text to append to.
* @param {string} moreText Text to append.
* @return {string} String with appended characters.
*/
const appendMoreText = ( text, moreText ) => {
return text.replace( /[\s|\.\,]+$/i, '' ) + moreText;
};
/**
* Limit words in string and returned trimmed version.
*
* @param {string} text Text to trim.
* @param {number} maxLength Number of countType to limit to.
* @param {string} moreText Appended to the trimmed string.
* @return {string} Trimmed string.
*/
const trimWords = ( text, maxLength, moreText = '&hellip;' ) => {
const textToTrim = removeTags( text );
const trimmedText = textToTrim
.split( ' ' )
.splice( 0, maxLength )
.join( ' ' );
return autop( appendMoreText( trimmedText, moreText ) );
};
/**
* Limit characters in string and returned trimmed version.
*
* @param {string} text Text to trim.
* @param {number} maxLength Number of countType to limit to.
* @param {boolean} includeSpaces Should spaces be included in the count.
* @param {string} moreText Appended to the trimmed string.
* @return {string} Trimmed string.
*/
const trimCharacters = (
text,
maxLength,
includeSpaces = true,
moreText = '&hellip;'
) => {
const textToTrim = removeTags( text );
const trimmedText = textToTrim.slice( 0, maxLength );
if ( includeSpaces ) {
return autop( appendMoreText( trimmedText, moreText ) );
}
const matchSpaces = trimmedText.match( /([\s]+)/g );
const spaceCount = matchSpaces ? matchSpaces.length : 0;
const trimmedTextExcludingSpaces = textToTrim.slice(
0,
maxLength + spaceCount
);
return autop( appendMoreText( trimmedTextExcludingSpaces, moreText ) );
};