Skip to content

Commit

Permalink
Merge branch 'master' into DropdownFixForIssue14815
Browse files Browse the repository at this point in the history
  • Loading branch information
cetincakiroglu authored Feb 23, 2024
2 parents b929c2b + f6e53aa commit 8f4e5ef
Show file tree
Hide file tree
Showing 50 changed files with 941 additions and 646 deletions.
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 10 additions & 8 deletions src/app/components/autofocus/autofocus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ export class AutoFocus {
ngAfterContentChecked() {
if (!this.focused) {
if (this.autofocus) {
const focusableElements = DomHandler.getFocusableElements(this.host.nativeElement);
setTimeout(() => {
const focusableElements = DomHandler.getFocusableElements(this.host.nativeElement);

if (focusableElements.length === 0) {
this.host.nativeElement.focus();
}
if (focusableElements.length > 0) {
focusableElements[0].focus();
}
if (focusableElements.length === 0) {
this.host.nativeElement.focus();
}
if (focusableElements.length > 0) {
focusableElements[0].focus();
}

this.focused = true;
this.focused = true;
});
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/checkbox/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ export class Checkbox implements ControlValueAccessor {
setDisabledState(val: boolean): void {
setTimeout(() => {
this.disabled = val;
this.cd.markForCheck();
});
this.cd.markForCheck();
}

checked() {
Expand Down
8 changes: 8 additions & 0 deletions src/app/components/chips/chips.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ describe('Chips', () => {
expect(inputEl.nativeElement.disabled).toEqual(false);
});

it('should set maxlength to input element', () => {
chips.max = 2;
fixture.detectChanges();

const inputEl = fixture.debugElement.query(By.css('input'));
expect(inputEl.attributes.maxlength).toEqual('2');
});

it('should delete item', () => {
chips.value = ['primeng'];
fixture.detectChanges();
Expand Down
6 changes: 6 additions & 0 deletions src/app/components/chips/chips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export const CHIPS_VALUE_ACCESSOR: any = {
#inputtext
type="text"
[attr.id]="inputId"
[attr.maxlength]="maxLength"
[attr.placeholder]="value && value.length ? null : placeholder"
[attr.tabindex]="tabindex"
(keydown)="onKeyDown($event)"
Expand Down Expand Up @@ -140,6 +141,11 @@ export class Chips implements AfterContentInit, ControlValueAccessor {
* @group Props
*/
@Input() max: number | undefined;
/**
* Maximum length of a chip.
* @group Props
*/
@Input() maxLength: number | undefined;
/**
* Defines a string that labels the input for accessibility.
* @group Props
Expand Down
6 changes: 2 additions & 4 deletions src/app/components/contextmenu/contextmenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1182,11 +1182,9 @@ export class ContextMenu implements OnInit, AfterContentInit, OnDestroy {
}

removeAppendedElements() {
if (this.appendTo) {
if (this.appendTo && this.containerViewChild) {
if (this.appendTo === 'body') {
if (this.containerViewChild) {
this.renderer.removeChild(this.document.body, this.containerViewChild.nativeElement);
}
this.renderer.removeChild(this.document.body, this.containerViewChild.nativeElement);
} else {
DomHandler.removeChild(this.containerViewChild.nativeElement, this.appendTo);
}
Expand Down
21 changes: 17 additions & 4 deletions src/app/components/dialog/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { WindowMinimizeIcon } from 'primeng/icons/windowminimize';
import { RippleModule } from 'primeng/ripple';
import { Nullable, VoidListener } from 'primeng/ts-helpers';
import { UniqueComponentId, ZIndexUtils } from 'primeng/utils';
import { ButtonModule } from 'primeng/button';

const showAnimation = animation([style({ transform: '{{transform}}', opacity: 0 }), animate('{{transition}}')]);

Expand All @@ -49,6 +50,7 @@ const hideAnimation = animation([animate('{{transition}}', style({ transform: '{
*ngIf="maskVisible"
[class]="maskStyleClass"
[style]="maskStyle"
(focus)="containerFocus($event)"
[ngClass]="{
'p-dialog-mask': true,
'p-component-overlay p-component-overlay-enter': this.modal,
Expand Down Expand Up @@ -91,7 +93,17 @@ const hideAnimation = animation([animate('{{transition}}', style({ transform: '{
</span>
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
<div class="p-dialog-header-icons">
<button *ngIf="maximizable" role="button" type="button" [ngClass]="{ 'p-dialog-header-icon p-dialog-header-maximize p-link': true }" (click)="maximize()" (keydown.enter)="maximize()" tabindex="-1" pRipple>
<button
*ngIf="maximizable"
role="button"
type="button"
[ngClass]="{ 'p-dialog-header-icon p-dialog-header-maximize p-link': true }"
(click)="maximize()"
(keydown.enter)="maximize()"
[attr.tabindex]="maximizable ? '0' : '-1'"
pRipple
pButton
>
<span *ngIf="maximizeIcon && !maximizeIconTemplate && !minimizeIconTemplate" class="p-dialog-header-maximize-icon" [ngClass]="maximized ? minimizeIcon : maximizeIcon"></span>
<ng-container *ngIf="!maximizeIcon">
<WindowMaximizeIcon *ngIf="!maximized && !maximizeIconTemplate" [styleClass]="'p-dialog-header-maximize-icon'" />
Expand All @@ -111,8 +123,9 @@ const hideAnimation = animation([animate('{{transition}}', style({ transform: '{
[attr.aria-label]="closeAriaLabel"
(click)="close($event)"
(keydown.enter)="close($event)"
[attr.tabindex]="closeTabindex"
pRipple
pButton
[attr.tabindex]="closeTabindex"
>
<ng-container *ngIf="!closeIconTemplate">
<span *ngIf="closeIcon" class="p-dialog-header-close-icon" [ngClass]="closeIcon"></span>
Expand Down Expand Up @@ -333,7 +346,7 @@ export class Dialog implements AfterContentInit, OnInit, OnDestroy {
* Index of the close button in tabbing order.
* @group Props
*/
@Input() closeTabindex: string = '-1';
@Input() closeTabindex: string = '0';
/**
* Name of the minimize icon.
* @group Props
Expand Down Expand Up @@ -1024,7 +1037,7 @@ export class Dialog implements AfterContentInit, OnInit, OnDestroy {
}

@NgModule({
imports: [CommonModule, FocusTrapModule, RippleModule, TimesIcon, WindowMaximizeIcon, WindowMinimizeIcon],
imports: [CommonModule, FocusTrapModule, ButtonModule, RippleModule, TimesIcon, WindowMaximizeIcon, WindowMinimizeIcon],
exports: [Dialog, SharedModule],
declarations: [Dialog]
})
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/dom/domhandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,8 @@ export class DomHandler {
let visibleFocusableElements = [];

for (let focusableElement of focusableElements) {
if (getComputedStyle(focusableElement).display != 'none' && getComputedStyle(focusableElement).visibility != 'hidden') visibleFocusableElements.push(focusableElement);
const computedStyle = getComputedStyle(focusableElement);
if (this.isVisible(focusableElement) && computedStyle.display != 'none' && computedStyle.visibility != 'hidden') visibleFocusableElements.push(focusableElement);
}

return visibleFocusableElements;
Expand Down
22 changes: 15 additions & 7 deletions src/app/components/dropdown/dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class DropdownItem {
<ng-container *ngIf="!selectedItemTemplate; else defaultPlaceholder">{{ label() === 'p-emptylabel' ? '&nbsp;' : label() }}</ng-container>
<ng-container *ngIf="selectedItemTemplate && selectedOption" [ngTemplateOutlet]="selectedItemTemplate" [ngTemplateOutletContext]="{ $implicit: selectedOption }"></ng-container>
<ng-template #defaultPlaceholder>
<span *ngIf="(modelValue() === undefined || modelValue() === null) && (label() === placeholder() || (label() && !placeholder()))">{{ label() === 'p-emptylabel' ? '&nbsp;' : placeholder() }}</span>
<span *ngIf="displayPlaceholder()">{{ label() === 'p-emptylabel' ? '&nbsp;' : placeholder() }}</span>
</ng-template>
</span>
<input
Expand Down Expand Up @@ -969,7 +969,8 @@ export class Dropdown implements OnInit, AfterViewInit, AfterContentInit, AfterV

if (visibleOptions && ObjectUtils.isNotEmpty(visibleOptions)) {
const selectedOptionIndex = this.findSelectedOptionIndex();
if (selectedOptionIndex !== -1 || modelValue === undefined || this.isModelValueNotSet() || this.editable) {

if (selectedOptionIndex !== -1 || modelValue === undefined || (typeof modelValue === 'string' && modelValue.length === 0) || this.isModelValueNotSet() || this.editable) {
this.selectedOption = visibleOptions[selectedOptionIndex];
}
}
Expand All @@ -985,12 +986,14 @@ export class Dropdown implements OnInit, AfterViewInit, AfterContentInit, AfterV
});
}

// modelValue equal to null would usually mean that modelValue was not set
// this method includes a test for the special case where modelValue is set because (modelValue is null and the selected option has a value of null)
private isModelValueNotSet(): boolean {
return this.modelValue() === null && !this.isOptionValueEqualsModelValue(this.selectedOption);
}

displayPlaceholder() {
return ObjectUtils.isEmpty(this.selectedOption) && this.label() === this.placeholder();
}

private getAllVisibleAndNonVisibleOptions() {
return this.group ? this.flatOptions(this.options) : this.options || [];
}
Expand Down Expand Up @@ -1190,7 +1193,11 @@ export class Dropdown implements OnInit, AfterViewInit, AfterContentInit, AfterV
}

isOptionDisabled(option: any) {
return this.optionDisabled ? ObjectUtils.resolveFieldData(option, this.optionDisabled) : option && option.disabled !== undefined ? option.disabled : false;
if (this.getOptionValue(this.modelValue()) === this.getOptionValue(option) || (this.getOptionLabel(this.modelValue() === this.getOptionLabel(option)) && option.disabled === false)) {
return false;
} else {
return this.optionDisabled ? ObjectUtils.resolveFieldData(option, this.optionDisabled) : option && option.disabled !== undefined ? option.disabled : false;
}
}

getOptionGroupLabel(optionGroup: any) {
Expand Down Expand Up @@ -1315,7 +1322,7 @@ export class Dropdown implements OnInit, AfterViewInit, AfterContentInit, AfterV
if (this.filterViewChild && this.filterViewChild.nativeElement) {
this.preventModelTouched = true;

if (this.autofocusFilter) {
if (this.autofocusFilter && !this.editable) {
this.filterViewChild.nativeElement.focus();
}
}
Expand Down Expand Up @@ -1728,7 +1735,7 @@ export class Dropdown implements OnInit, AfterViewInit, AfterContentInit, AfterV
}

onFirstHiddenFocus(event) {
const focusableEl = event.relatedTarget === this.focusInputViewChild?.nativeElement ? DomHandler.getFirstFocusableElement(this.overlayViewChild.el.nativeElement, ':not(.p-hidden-focusable)') : this.focusInputViewChild.nativeElement;
const focusableEl = event.relatedTarget === this.focusInputViewChild?.nativeElement ? DomHandler.getFirstFocusableElement(this.overlayViewChild.el?.nativeElement, ':not(.p-hidden-focusable)') : this.focusInputViewChild?.nativeElement;
DomHandler.focus(focusableEl);
}

Expand Down Expand Up @@ -1833,6 +1840,7 @@ export class Dropdown implements OnInit, AfterViewInit, AfterContentInit, AfterV
public clear(event?: Event) {
this.updateModel(null, event);
this.clearEditableLabel();
this.onModelTouched();
this.onChange.emit({ originalEvent: event, value: this.value });
this.onClear.emit(event);
this.resetFilter();
Expand Down
3 changes: 3 additions & 0 deletions src/app/components/fieldset/fieldset.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
@layer primeng {
.p-fieldset{
min-width: initial;
}
.p-fieldset-legend > a,
.p-fieldset-legend > span {
display: flex;
Expand Down
14 changes: 7 additions & 7 deletions src/app/components/fileupload/fileupload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,11 +557,10 @@ export class FileUpload implements AfterViewInit, AfterContentInit, OnInit, OnDe

this.onSelect.emit({ originalEvent: event, files: files, currentFiles: this.files });

if (this.fileLimit) {
this.checkFileLimit();
}
// this will check the fileLimit with the uploaded files
this.checkFileLimit(files);

if (this.hasFiles() && this.auto && (!(this.mode === 'advanced') || !this.isFileLimitExceeded())) {
if (this.hasFiles() && this.auto && !(this.mode === 'advanced') && !this.isFileLimitExceeded()) {
this.upload();
}

Expand Down Expand Up @@ -739,7 +738,7 @@ export class FileUpload implements AfterViewInit, AfterContentInit, OnInit, OnDe
this.clearInputElement();
this.onRemove.emit({ originalEvent: event, file: this.files[index] });
this.files.splice(index, 1);
this.checkFileLimit();
this.checkFileLimit(this.files);
}

isFileLimitExceeded() {
Expand All @@ -761,9 +760,10 @@ export class FileUpload implements AfterViewInit, AfterContentInit, OnInit, OnDe
}
}

checkFileLimit() {
checkFileLimit(files: File[]) {
this.msgs ??= [];
if (this.isFileLimitExceeded()) {
const hasExistingValidationMessages = this.msgs.length > 0 && this.fileLimit < files.length;
if (this.isFileLimitExceeded() || hasExistingValidationMessages) {
this.msgs.push({
severity: 'error',
summary: this.invalidFileLimitMessageSummary.replace('{0}', (this.fileLimit as number).toString()),
Expand Down
7 changes: 3 additions & 4 deletions src/app/components/focustrap/focustrap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DomHandler } from 'primeng/dom';

import { CommonModule } from '@angular/common';
import { Directive, ElementRef, HostListener, Input, NgModule } from '@angular/core';
import { Directive, ElementRef, HostListener, Input, NgModule, inject } from '@angular/core';
/**
* Focus Trap keeps focus within a certain DOM element while tabbing.
* @group Components
Expand All @@ -19,15 +19,14 @@ export class FocusTrap {
*/
@Input() pFocusTrapDisabled: boolean = false;

constructor(public el: ElementRef) {}
host: ElementRef = inject(ElementRef);

@HostListener('keydown.tab', ['$event'])
@HostListener('keydown.shift.tab', ['$event'])
onkeydown(e: KeyboardEvent) {
if (this.pFocusTrapDisabled !== true) {
e.preventDefault();
const focusableElement = DomHandler.getNextFocusableElement(this.el.nativeElement, e.shiftKey);

const focusableElement = DomHandler.getNextFocusableElement(this.host.nativeElement, e.shiftKey);
if (focusableElement) {
focusableElement.focus();
focusableElement.select?.();
Expand Down
15 changes: 14 additions & 1 deletion src/app/components/multiselect/multiselect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1042,8 +1042,12 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
return this.config.getTranslation(TranslationKeys.ARIA)['listLabel'];
}

private getAllVisibleAndNonVisibleOptions() {
return this.group ? this.flatOptions(this.options) : this.options || [];
}

visibleOptions = computed(() => {
const options = this.group ? this.flatOptions(this.options) : this.options || [];
const options = this.getAllVisibleAndNonVisibleOptions();
const isArrayOfObjects = ObjectUtils.isArray(options) && ObjectUtils.isObject(options[0]);

if (this._filterValue()) {
Expand Down Expand Up @@ -1834,8 +1838,17 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft
.map((option) => this.getOptionValue(option));

this.updateModel(value, event);

// because onToggleAll could have been called during filtering, this additional test needs to be performed before calling onSelectAllChange.emit
if (!value.length || value.length === this.getAllVisibleAndNonVisibleOptions().length) {
this.onSelectAllChange.emit({
originalEvent: event,
checked: !!value.length
});
}
}

this.onChange.emit({ originalEvent: event, value: this.value });
DomHandler.focus(this.headerCheckboxViewChild?.nativeElement);
this.headerCheckboxFocus = true;

Expand Down
1 change: 0 additions & 1 deletion src/app/components/sidebar/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ const hideAnimation = animation([animate('{{transition}}', style({ transform: '{
role="complementary"
[attr.data-pc-name]="'sidebar'"
[attr.data-pc-section]="'root'"
[attr.aria-modal]="modal"
(keydown)="onKeyDown($event)"
>
<ng-container *ngIf="headlessTemplate; else notHeadless">
Expand Down
Loading

0 comments on commit 8f4e5ef

Please sign in to comment.