rebase on oct-10-2023
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
AttributeQuery,
|
||||
AttributeTerm,
|
||||
} from '@woocommerce/types';
|
||||
import { sortBy } from 'lodash';
|
||||
import { sort } from 'fast-sort';
|
||||
|
||||
/**
|
||||
* Given a query object, removes an attribute filter by a single slug.
|
||||
@@ -51,7 +51,7 @@ export const removeAttributeFilterBySlug = (
|
||||
returnQuery.push( currentQuery );
|
||||
}
|
||||
|
||||
setQuery( sortBy( returnQuery, 'attribute' ) );
|
||||
setQuery( sort( returnQuery ).asc( 'attribute' ) );
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -88,7 +88,7 @@ export const updateAttributeFilter = (
|
||||
operator,
|
||||
slug: attributeTerms.map( ( { slug } ) => slug ).sort(),
|
||||
} );
|
||||
setQuery( sortBy( returnQuery, 'attribute' ) );
|
||||
setQuery( sort( returnQuery ).asc( 'attribute' ) );
|
||||
}
|
||||
|
||||
return returnQuery;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getSettingWithCoercion } from '@woocommerce/settings';
|
||||
import { isBoolean } from '@woocommerce/types';
|
||||
|
||||
const filteringForPhpTemplate = getSettingWithCoercion(
|
||||
'is_rendering_php_template',
|
||||
'isRenderingPhpTemplate',
|
||||
false,
|
||||
isBoolean
|
||||
);
|
||||
@@ -34,6 +34,34 @@ export function getUrlParameter( name: string ) {
|
||||
*/
|
||||
export function changeUrl( newUrl: string ) {
|
||||
if ( filteringForPhpTemplate ) {
|
||||
/**
|
||||
* We want to remove page number from URL whenever filters are changed.
|
||||
* This will move the user to the first page of results.
|
||||
*
|
||||
* There are following page number formats:
|
||||
* 1. query-{number}-page={number} (ex. query-1-page=2)
|
||||
* - ref: https://github.com/WordPress/gutenberg/blob/5693a62214b6c76d3dc5f3f69d8aad187748af79/packages/block-library/src/query-pagination-numbers/index.php#L18
|
||||
* 2. query-page={number} (ex. query-page=2)
|
||||
* - ref: same as above
|
||||
* 3. page/{number} (ex. page/2) (Default WordPress pagination format)
|
||||
*/
|
||||
newUrl = newUrl.replace(
|
||||
/(?:query-(?:\d+-)?page=(\d+))|(?:page\/(\d+))/g,
|
||||
''
|
||||
);
|
||||
|
||||
/**
|
||||
* If the URL ends with '?', we remove the trailing '?' from the URL.
|
||||
* The trailing '?' in a URL is unnecessary and can cause the page to
|
||||
* reload, which can negatively affect performance. By removing the '?',
|
||||
* we prevent this unnecessary reload. This is safe to do even if there
|
||||
* are query parameters, as they will not be affected by the removal
|
||||
* of a trailing '?'.
|
||||
*/
|
||||
if ( newUrl.endsWith( '?' ) ) {
|
||||
newUrl = newUrl.slice( 0, -1 );
|
||||
}
|
||||
|
||||
window.location.href = newUrl;
|
||||
} else {
|
||||
window.history.replaceState( {}, '', newUrl );
|
||||
|
||||
@@ -3,7 +3,10 @@ export * from './attributes-query';
|
||||
export * from './attributes';
|
||||
export * from './filters';
|
||||
export * from './notices';
|
||||
export * from './object-operations';
|
||||
export * from './products';
|
||||
export * from './shared-attributes';
|
||||
export * from './useThrottle';
|
||||
export * from './sanitize-html';
|
||||
export * from './is-site-editor-page';
|
||||
export * from './is-widget-editor-page';
|
||||
export * from './trim-words';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { isObject } from '../types/type-guards';
|
||||
|
||||
export const isSiteEditorPage = ( store: unknown ): boolean => {
|
||||
if ( isObject( store ) ) {
|
||||
const editedPostType = (
|
||||
store as {
|
||||
getEditedPostType: () => string;
|
||||
}
|
||||
).getEditedPostType();
|
||||
|
||||
return (
|
||||
editedPostType === 'wp_template' ||
|
||||
editedPostType === 'wp_template_part'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { isObject } from '../types/type-guards';
|
||||
|
||||
export const isWidgetEditorPage = ( store: unknown ): boolean => {
|
||||
if ( isObject( store ) ) {
|
||||
const widgetAreas = (
|
||||
store as {
|
||||
getWidgetAreas: () => string;
|
||||
}
|
||||
).getWidgetAreas();
|
||||
|
||||
return Array.isArray( widgetAreas ) && widgetAreas.length > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Returns an object without a key.
|
||||
*/
|
||||
export function objectOmit< T, K extends keyof T >( obj: T, key: K ) {
|
||||
const { [ key ]: omit, ...rest } = obj;
|
||||
|
||||
return rest;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export default {
|
||||
*/
|
||||
columns: {
|
||||
type: 'number',
|
||||
default: getSetting( 'default_columns', 3 ),
|
||||
default: getSetting( 'defaultColumns', 3 ),
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
*/
|
||||
rows: {
|
||||
type: 'number',
|
||||
default: getSetting( 'default_rows', 3 ),
|
||||
default: getSetting( 'defaultRows', 3 ),
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
appendMoreText,
|
||||
removeTags,
|
||||
trimCharacters,
|
||||
trimWords,
|
||||
} from '@woocommerce/utils';
|
||||
|
||||
describe( 'trim-words', () => {
|
||||
describe( 'removeTags', () => {
|
||||
it( 'Removes HTML tags from a string', () => {
|
||||
const string = '<div><a href="/index.php">trim-words.ts</a></div>';
|
||||
const trimmedString = removeTags( string );
|
||||
expect( trimmedString ).toEqual( 'trim-words.ts' );
|
||||
} );
|
||||
} );
|
||||
describe( 'appendMoreText', () => {
|
||||
it( 'Removes trailing punctuation and appends some characters to a string', () => {
|
||||
const string = 'trim-words.ts,';
|
||||
const appendedString = appendMoreText( string, '...' );
|
||||
expect( appendedString ).toEqual( 'trim-words.ts...' );
|
||||
} );
|
||||
} );
|
||||
describe( 'trimWords', () => {
|
||||
const testContent =
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.';
|
||||
it( 'Limits words in string and returns trimmed version', () => {
|
||||
const trimmedString = trimWords( testContent, 3 );
|
||||
expect( trimmedString ).toBe(
|
||||
'<p>Lorem ipsum dolor…</p>\n'
|
||||
);
|
||||
} );
|
||||
it( 'Limits words in string and returns trimmed version with custom moreText', () => {
|
||||
const trimmedString = trimWords( testContent, 4, '... read more.' );
|
||||
expect( trimmedString ).toEqual(
|
||||
'<p>Lorem ipsum dolor sit... read more.</p>\n'
|
||||
);
|
||||
} );
|
||||
it( 'Limits words in string and returns trimmed version without autop', () => {
|
||||
const trimmedString = trimWords(
|
||||
testContent,
|
||||
3,
|
||||
'…',
|
||||
false
|
||||
);
|
||||
expect( trimmedString ).toEqual( 'Lorem ipsum dolor…' );
|
||||
} );
|
||||
it( 'does not append anything if the text is shorter than the trim limit', () => {
|
||||
const trimmedString = trimWords( testContent, 100 );
|
||||
expect( trimmedString ).toEqual( '<p>' + testContent + '</p>\n' );
|
||||
} );
|
||||
} );
|
||||
describe( 'trimCharacters', () => {
|
||||
const testContent = 'Lorem ipsum dolor sit amet.';
|
||||
|
||||
it( 'Limits characters in string and returns trimmed version including spaces', () => {
|
||||
const result = trimCharacters( testContent, 10 );
|
||||
expect( result ).toEqual( '<p>Lorem ipsu…</p>\n' );
|
||||
} );
|
||||
it( 'Limits characters in string and returns trimmed version excluding spaces', () => {
|
||||
const result = trimCharacters( testContent, 10, false );
|
||||
expect( result ).toEqual( '<p>Lorem ipsum…</p>\n' );
|
||||
} );
|
||||
it( 'Limits characters in string and returns trimmed version with custom moreText', () => {
|
||||
const result = trimCharacters(
|
||||
testContent,
|
||||
10,
|
||||
false,
|
||||
'... read more.'
|
||||
);
|
||||
expect( result ).toEqual( '<p>Lorem ipsum... read more.</p>\n' );
|
||||
} );
|
||||
it( 'Limits characters in string and returns trimmed version without autop', () => {
|
||||
const result = trimCharacters(
|
||||
testContent,
|
||||
10,
|
||||
false,
|
||||
'... read more.',
|
||||
false
|
||||
);
|
||||
expect( result ).toEqual( 'Lorem ipsum... read more.' );
|
||||
} );
|
||||
|
||||
it( 'does not append anything if the text is shorter than the trim limit', () => {
|
||||
const trimmedString = trimCharacters( testContent, 1000 );
|
||||
expect( trimmedString ).toEqual( '<p>' + testContent + '</p>\n' );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { autop } from '@wordpress/autop';
|
||||
|
||||
/**
|
||||
* Remove HTML tags from a string.
|
||||
*
|
||||
* @param {string} htmlString String to remove tags from.
|
||||
* @return {string} Plain text string.
|
||||
*/
|
||||
export const removeTags = ( htmlString: string ) => {
|
||||
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.
|
||||
*/
|
||||
export const appendMoreText = ( text: string, moreText: string ) => {
|
||||
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.
|
||||
* @param {string} useAutop Whether to format with autop before returning.
|
||||
* @return {string} Trimmed string.
|
||||
*/
|
||||
export const trimWords = (
|
||||
text: string,
|
||||
maxLength: number,
|
||||
moreText = '…',
|
||||
useAutop = true
|
||||
) => {
|
||||
const textToTrim = removeTags( text );
|
||||
const trimmedText = textToTrim
|
||||
.split( ' ' )
|
||||
.splice( 0, maxLength )
|
||||
.join( ' ' );
|
||||
|
||||
if ( trimmedText === textToTrim ) {
|
||||
return useAutop ? autop( textToTrim ) : textToTrim;
|
||||
}
|
||||
|
||||
if ( ! useAutop ) {
|
||||
return appendMoreText( trimmedText, moreText );
|
||||
}
|
||||
|
||||
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.
|
||||
* @param {string} useAutop Whether to format with autop before returning.
|
||||
* @return {string} Trimmed string.
|
||||
*/
|
||||
export const trimCharacters = (
|
||||
text: string,
|
||||
maxLength: number,
|
||||
includeSpaces = true,
|
||||
moreText = '…',
|
||||
useAutop = true
|
||||
) => {
|
||||
const textToTrim = removeTags( text );
|
||||
const trimmedText = textToTrim.slice( 0, maxLength );
|
||||
|
||||
if ( trimmedText === textToTrim ) {
|
||||
return useAutop ? autop( textToTrim ) : textToTrim;
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
if ( ! useAutop ) {
|
||||
return appendMoreText( trimmedTextExcludingSpaces, moreText );
|
||||
}
|
||||
|
||||
return autop( appendMoreText( trimmedTextExcludingSpaces, moreText ) );
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
/* eslint-disable you-dont-need-lodash-underscore/throttle */
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { DebouncedFunc, throttle, ThrottleSettings } from 'lodash';
|
||||
import { useCallback, useEffect, useRef } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Throttles a function inside a React functional component
|
||||
*/
|
||||
// Disabling this as lodash expects this and I didn't make using `unknown`
|
||||
// work in practice.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function useThrottle< T extends ( ...args: any[] ) => any >(
|
||||
cb: T,
|
||||
delay: number,
|
||||
options?: ThrottleSettings
|
||||
): DebouncedFunc< T > {
|
||||
const cbRef = useRef( cb );
|
||||
|
||||
useEffect( () => {
|
||||
cbRef.current = cb;
|
||||
} );
|
||||
|
||||
// Disabling because we can't pass an arrow function in this case
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const throttledCb = useCallback(
|
||||
throttle( ( ...args ) => cbRef.current( ...args ), delay, options ),
|
||||
[ delay ]
|
||||
);
|
||||
|
||||
return throttledCb;
|
||||
}
|
||||
Reference in New Issue
Block a user