diff --git a/api-generator/components/autocomplete.js b/api-generator/components/autocomplete.js index bc2468e29..f745c56f2 100644 --- a/api-generator/components/autocomplete.js +++ b/api-generator/components/autocomplete.js @@ -387,11 +387,15 @@ const AutoCompleteSlots = [ }, { name: 'content', - description: 'Custom content for the virtual scroller' + description: 'Custom content for the virtual scroller.' }, { name: 'loader', - description: 'Custom content for the virtual scroller loader items' + description: 'Custom content for the virtual scroller loader items.' + }, + { + name: 'empty', + description: 'Custom empty template when there is no data to display.' } ]; diff --git a/api-generator/components/sidebar.js b/api-generator/components/sidebar.js index 9b17f9caa..039930a1c 100644 --- a/api-generator/components/sidebar.js +++ b/api-generator/components/sidebar.js @@ -46,6 +46,12 @@ const SidebarProps = [ type: 'string', default: 'close', description: 'Aria label of the close icon.' + }, + { + name: 'blockScroll', + type: 'boolean', + default: 'false', + description: 'Whether background scroll should be blocked when sidebar is visible.' } ]; diff --git a/components/api/test/FilterService.spec.js b/components/api/test/FilterService.spec.js new file mode 100644 index 000000000..b9ffef3bd --- /dev/null +++ b/components/api/test/FilterService.spec.js @@ -0,0 +1,298 @@ +import { afterEach } from 'vitest'; +import FilterService from '../FilterService'; +const filters = FilterService.filters; + +import { ObjectUtils } from 'primevue/utils'; + +afterEach(() => { + vi.restoreAllMocks(); +}); + +const checkParametersNullOrUndefined = (filterType) => { + it('When value parameter is undefined', () => { + expect(filters[filterType]('value', undefined)).toBeTruthy(); + }); + + it('When value parameter is null', () => { + expect(filters[filterType]('value', null)).toBeTruthy(); + }); + + it('When filter parameter is undefined', () => { + expect(filters[filterType](undefined, 'filter')).toBeFalsy(); + }); + + it('When filter parameter is null', () => { + expect(filters[filterType](undefined, 'filter')).toBeFalsy(); + }); +}; + +describe('FilterService', () => { + describe('StartsWith filter test', () => { + checkParametersNullOrUndefined('startsWith'); + it('When value and filter parameter is not null or undefined', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockReturnValue('value'); + + const startsWith = filters.startsWith('value', 'filter', 'tr'); + + expect(startsWith).toBeTruthy(); + }); + }); + + describe('Contains filter test', () => { + checkParametersNullOrUndefined('contains'); + + it('When value and filter parameter is not null or undefined', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockReturnValue('value'); + + const contains = filters.contains('value', 'filter', 'tr'); + + expect(contains).toBeTruthy(); + }); + }); + + describe('NotContains filter test', () => { + checkParametersNullOrUndefined('notContains'); + + it('When value and filter parameter is not null or undefined', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockReturnValue('value'); + + const notContains = filters.notContains('value', 'filter', 'tr'); + + expect(notContains).toBeFalsy(); + }); + }); + + describe('endsWith filter test', () => { + checkParametersNullOrUndefined('endsWith'); + + it('When value and filter parameter is not null or undefined', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockReturnValue('value'); + + const endsWith = filters.endsWith('value', 'filter', 'tr'); + + expect(endsWith).toBeTruthy(); + }); + }); + + describe('equals filter test', () => { + checkParametersNullOrUndefined('equals'); + + it('When value and filter parameter has getTime property', () => { + const getTimeMock = vi.fn(() => true); + const equals = filters.equals({ getTime: getTimeMock }, { getTime: getTimeMock }, 'tr'); + + expect(equals).toBeTruthy(); + }); + + it('When value and filter parameter is not null or undefined', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockReturnValue('value'); + + const equals = filters.equals('value', 'filter', 'tr'); + + expect(equals).toBeTruthy(); + }); + }); + + describe('notEquals filter test', () => { + it('When filter parameter is undefined', () => { + expect(filters.notEquals('value', undefined)).toBeFalsy(); + }); + + it('When value parameter is undefined', () => { + expect(filters.notEquals(undefined, 'filter')).toBeTruthy(); + }); + + it('When value parameter is null', () => { + expect(filters.notEquals(undefined, 'filter')).toBeTruthy(); + }); + + it('When value and filter parameter has getTime property', () => { + const getTimeMock = vi.fn(() => true); + const notEquals = filters.notEquals({ getTime: getTimeMock }, { getTime: getTimeMock }, 'tr'); + + expect(notEquals).toBeFalsy(); + }); + + it('When value and filter parameter is not null or undefined', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockReturnValue('value'); + + const notEquals = filters.notEquals('value', 'filter', 'tr'); + + expect(notEquals).toBeFalsy(); + }); + }); + + describe('in filter test', () => { + checkParametersNullOrUndefined('in'); + + it('When value parameter equal to any filter word', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockImplementation((value, filter) => value === filter); + + const inFilter = filters.in('e', 'filter'); + + expect(inFilter).toBeTruthy(); + }); + + it('When value parameter not equal to any filter word', () => { + vi.spyOn(ObjectUtils, 'removeAccents').mockImplementation((value, filter) => value === filter); + + const inFilter = filters.in('d', 'filter'); + + expect(inFilter).toBeFalsy(); + }); + }); + + describe('between filter test', () => { + checkParametersNullOrUndefined('between'); + it('When value has getTime func and smaller than filter[0]', () => { + const filterGetTime = vi.fn(() => 1); + const filterGetTime1 = vi.fn(() => 3); + const valueGetTime = vi.fn(() => 2); + + const between = filters.between({ getTime: valueGetTime }, [{ getTime: filterGetTime }, { getTime: filterGetTime1 }], 'tr'); + + expect(between).toBeTruthy(); + }); + + it('When value has getTime func and smaller than filter[0]', () => { + const filter = 1; + const filter1 = 2; + const value = 2; + + const between = filters.between(value, [filter, filter1], 'tr'); + + expect(between).toBeTruthy(); + }); + }); + + describe('lt filter test', () => { + checkParametersNullOrUndefined('lt'); + it('When value has getTime func and smaller than filter', () => { + const filterGetTime = vi.fn(() => 2); + const valueGetTime = vi.fn(() => 1); + + const lt = filters.lt({ getTime: valueGetTime }, { getTime: filterGetTime }); + + expect(lt).toBeTruthy(); + }); + + it('When value smaller than filter', () => { + const filter = 2; + const value = 1; + + const lt = filters.lt(value, filter); + + expect(lt).toBeTruthy(); + }); + }); + + describe('lte filter test', () => { + checkParametersNullOrUndefined('lte'); + it('When value has getTime func and smaller than filter', () => { + const filterGetTime = vi.fn(() => 2); + const valueGetTime = vi.fn(() => 1); + + const lte = filters.lte({ getTime: valueGetTime }, { getTime: filterGetTime }); + + expect(lte).toBeTruthy(); + }); + + it('When value smaller than filter', () => { + const filter = 2; + const value = 1; + + const lte = filters.lte(value, filter); + + expect(lte).toBeTruthy(); + }); + }); + + describe('gt filter test', () => { + checkParametersNullOrUndefined('gt'); + it('When value has getTime func and smaller than filter[0]', () => { + const filterGetTime = vi.fn(() => 2); + const valueGetTime = vi.fn(() => 1); + + const gt = filters.gt({ getTime: valueGetTime }, { getTime: filterGetTime }); + + expect(gt).toBeFalsy(); + }); + + it('When value smaller than filter[0]', () => { + const filter = 2; + const value = 1; + + const gt = filters.gt(value, filter); + + expect(gt).toBeFalsy(); + }); + }); + describe('gte filter test', () => { + checkParametersNullOrUndefined('gte'); + it('When value has getTime func and smaller than filter[0]', () => { + const filterGetTime = vi.fn(() => 2); + const valueGetTime = vi.fn(() => 1); + + const gte = filters.gte({ getTime: valueGetTime }, { getTime: filterGetTime }); + + expect(gte).toBeFalsy(); + }); + + it('When value parameter smaller than filter[0]', () => { + const filter = 2; + const value = 1; + + const gte = filters.gte(value, filter); + + expect(gte).toBeFalsy(); + }); + }); + + describe('dateIs filter test', () => { + checkParametersNullOrUndefined('dateIs'); + it('When value and filter are equal', () => { + const filter = new Date(1993, 6, 28, 14, 39, 7); + const value = new Date(1993, 6, 28, 14, 39, 7); + + const dateIs = filters.dateIs(value, filter); + + expect(dateIs).toBeTruthy(); + }); + }); + + describe('dateIsNot filter test', () => { + checkParametersNullOrUndefined('dateIsNot'); + it('When value and filter are not equal', () => { + const filter = new Date(1993, 6, 28, 14, 39, 7); + const value = new Date(1993, 6, 28, 14, 39, 7); + + const dateIsNot = filters.dateIsNot(value, filter); + + expect(dateIsNot).toBeFalsy(); + }); + }); + + describe('dateBefore filter test', () => { + checkParametersNullOrUndefined('dateBefore'); + it('When filter value bigger than value', () => { + const filter = new Date(1996, 6, 28, 14, 39, 8); + const value = new Date(1993, 6, 28, 14, 39, 7); + + const dateBefore = filters.dateBefore(value, filter); + + expect(dateBefore).toBeTruthy(); + }); + }); + + describe('dateAfter filter test', () => { + checkParametersNullOrUndefined('dateAfter'); + it('When value is not smaller than value', () => { + const filter = new Date(1996, 6, 28, 14, 39, 8); + const value = new Date(1993, 6, 28, 14, 39, 7); + + const dateAfter = filters.dateAfter(value, filter); + + expect(dateAfter).toBeFalsy(); + }); + }); +}); diff --git a/components/autocomplete/AutoComplete.d.ts b/components/autocomplete/AutoComplete.d.ts index 02546022f..f1c608040 100755 --- a/components/autocomplete/AutoComplete.d.ts +++ b/components/autocomplete/AutoComplete.d.ts @@ -381,6 +381,10 @@ export interface AutoCompleteSlots { */ options: any[]; }) => VNode[]; + /** + * Custom empty template when there is no data to display. + */ + empty: () => VNode[]; } export declare type AutoCompleteEmits = { diff --git a/components/autocomplete/AutoComplete.vue b/components/autocomplete/AutoComplete.vue index 8730d6798..a3ff29818 100755 --- a/components/autocomplete/AutoComplete.vue +++ b/components/autocomplete/AutoComplete.vue @@ -119,6 +119,9 @@ +
@@ -323,7 +326,7 @@ export default { watch: { suggestions() { if (this.searching) { - ObjectUtils.isNotEmpty(this.suggestions) ? this.show() : this.hide(); + ObjectUtils.isNotEmpty(this.suggestions) ? this.show() : !!this.$slots.empty ? this.show() : this.hide(); this.focusedOptionIndex = this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1; this.searching = false; } @@ -663,29 +666,19 @@ export default { this.multiple && event.stopPropagation(); // To prevent onArrowRightKeyOnMultiple method }, onHomeKey(event) { - const target = event.currentTarget; - const len = target.value.length; - - if (event.shiftKey) { - event.currentTarget.setSelectionRange(0, len); - } else { - event.currentTarget.setSelectionRange(0, 0); - } + const { currentTarget } = event; + const len = currentTarget.value.length; + currentTarget.setSelectionRange(0, event.shiftKey ? len : 0); this.focusedOptionIndex = -1; event.preventDefault(); }, onEndKey(event) { - const target = event.currentTarget; - const len = target.value.length; - - if (event.shiftKey) { - event.currentTarget.setSelectionRange(0, len); - } else { - target.setSelectionRange(len, len); - } + const { currentTarget } = event; + const len = currentTarget.value.length; + currentTarget.setSelectionRange(event.shiftKey ? 0 : len, len); this.focusedOptionIndex = -1; event.preventDefault(); diff --git a/components/breadcrumb/Breadcrumb.vue b/components/breadcrumb/Breadcrumb.vue index 730bb5555..174fecc3b 100755 --- a/components/breadcrumb/Breadcrumb.vue +++ b/components/breadcrumb/Breadcrumb.vue @@ -1,7 +1,7 @@