Skip to content

Commit

Permalink
Merge pull request #11816 from primefaces/issue-11807
Browse files Browse the repository at this point in the history
Issue 11807
  • Loading branch information
cetincakiroglu authored Aug 11, 2022
2 parents ef4510b + 8bd469c commit 7c6c1e4
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 11 deletions.
13 changes: 7 additions & 6 deletions src/app/components/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {DomHandler, ConnectedOverlayScrollHandler} from 'primeng/dom';
import {ObjectUtils, UniqueComponentId, ZIndexUtils} from 'primeng/utils';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
import {Scroller, ScrollerModule, ScrollerOptions} from 'primeng/scroller';
import {AutoFocusModule} from 'primeng/autofocus';

export const AUTOCOMPLETE_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
Expand All @@ -20,9 +21,9 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = {
selector: 'p-autoComplete',
template: `
<span #container [ngClass]="{'p-autocomplete p-component':true,'p-autocomplete-dd':dropdown,'p-autocomplete-multiple':multiple}" [ngStyle]="style" [class]="styleClass">
<input *ngIf="!multiple" #in [attr.type]="type" [attr.id]="inputId" [ngStyle]="inputStyle" [class]="inputStyleClass" [autocomplete]="autocomplete" [attr.required]="required" [attr.name]="name"
<input [pAutoFocus]="autofocus" *ngIf="!multiple" #in [attr.type]="type" [attr.id]="inputId" [ngStyle]="inputStyle" [class]="inputStyleClass" [autocomplete]="autocomplete" [attr.required]="required" [attr.name]="name"
class="p-autocomplete-input p-inputtext p-component" [ngClass]="{'p-autocomplete-dd-input':dropdown,'p-disabled': disabled}" [value]="inputFieldValue" aria-autocomplete="list" role="searchbox"
(click)="onInputClick($event)" (input)="onInput($event)" (keydown)="onKeydown($event)" (keyup)="onKeyup($event)" [attr.autofocus]="autofocus" (focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (change)="onInputChange($event)" (paste)="onInputPaste($event)"
(click)="onInputClick($event)" (input)="onInput($event)" (keydown)="onKeydown($event)" (keyup)="onKeyup($event)" (focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (change)="onInputChange($event)" (paste)="onInputPaste($event)"
[attr.placeholder]="placeholder" [attr.size]="size" [attr.maxlength]="maxlength" [attr.tabindex]="tabindex" [readonly]="readonly" [disabled]="disabled" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy" [attr.aria-required]="required">
<i *ngIf="!multiple && filled && !disabled && showClear" class="p-autocomplete-clear-icon pi pi-times" (click)="clear()"></i>
<i *ngIf="multiple && filled && !disabled && showClear" class="p-autocomplete-clear-icon pi pi-times" (click)="clear()"></i>
Expand All @@ -33,8 +34,8 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = {
<span class="p-autocomplete-token-icon pi pi-times-circle" (click)="removeItem(token)" *ngIf="!disabled && !readonly"></span>
</li>
<li class="p-autocomplete-input-token">
<input #multiIn [attr.type]="type" [attr.id]="inputId" [disabled]="disabled" [attr.placeholder]="(value&&value.length ? null : placeholder)" [attr.tabindex]="tabindex" [attr.maxlength]="maxlength" (input)="onInput($event)" (click)="onInputClick($event)"
(keydown)="onKeydown($event)" [readonly]="readonly" (keyup)="onKeyup($event)" [attr.autofocus]="autofocus" (focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (change)="onInputChange($event)" (paste)="onInputPaste($event)" [autocomplete]="autocomplete"
<input [pAutoFocus]="autofocus" #multiIn [attr.type]="type" [attr.id]="inputId" [disabled]="disabled" [attr.placeholder]="(value&&value.length ? null : placeholder)" [attr.tabindex]="tabindex" [attr.maxlength]="maxlength" (input)="onInput($event)" (click)="onInputClick($event)"
(keydown)="onKeydown($event)" [readonly]="readonly" (keyup)="onKeyup($event)" (focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (change)="onInputChange($event)" (paste)="onInputPaste($event)" [autocomplete]="autocomplete"
[ngStyle]="inputStyle" [class]="inputStyleClass" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy" [attr.aria-required]="required"
aria-autocomplete="list" [attr.aria-controls]="listId" role="searchbox" [attr.aria-expanded]="overlayVisible" aria-haspopup="true" [attr.aria-activedescendant]="'p-highlighted-option'">
</li>
Expand Down Expand Up @@ -105,7 +106,7 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = {
host: {
'class': 'p-element p-inputwrapper',
'[class.p-inputwrapper-filled]': 'filled',
'[class.p-inputwrapper-focus]': '(focus && !disabled) || overlayVisible',
'[class.p-inputwrapper-focus]': '((focus && !disabled) || autofocus) || overlayVisible',
'[class.p-autocomplete-clearable]': 'showClear && !disabled'
},
providers: [AUTOCOMPLETE_VALUE_ACCESSOR],
Expand Down Expand Up @@ -1043,7 +1044,7 @@ export class AutoComplete implements AfterViewChecked,AfterContentInit,OnDestroy
}

@NgModule({
imports: [CommonModule,InputTextModule,ButtonModule,SharedModule,RippleModule,ScrollerModule],
imports: [CommonModule,InputTextModule,ButtonModule,SharedModule,RippleModule,ScrollerModule,AutoFocusModule],
exports: [AutoComplete,SharedModule,ScrollerModule],
declarations: [AutoComplete]
})
Expand Down
43 changes: 43 additions & 0 deletions src/app/components/autofocus/autofocus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {NgModule,Directive,ElementRef,Input} from '@angular/core';
import {CommonModule} from '@angular/common';
import {DomHandler} from 'primeng/dom';

@Directive({
selector: '[pAutoFocus]',
host: {
'class': 'p-element'
}
})

export class AutoFocus {

constructor (private host: ElementRef) {}

@Input('pAutoFocus') autofocus: boolean;

focused: boolean = false;

ngAfterContentChecked () {
if(!this.focused) {
if(this.autofocus) {
const focusableElements = DomHandler.getFocusableElements(this.host.nativeElement);

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

this.focused = true;
}
}
}
}

@NgModule({
imports: [CommonModule],
exports: [AutoFocus],
declarations: [AutoFocus]
})
export class AutoFocusModule { }
6 changes: 6 additions & 0 deletions src/app/components/autofocus/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "ng-packagr/ng-package.schema.json",
"lib": {
"entryFile": "public_api.ts"
}
}
1 change: 1 addition & 0 deletions src/app/components/autofocus/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './autofocus';
5 changes: 3 additions & 2 deletions src/app/components/dropdown/dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
import {TooltipModule} from 'primeng/tooltip';
import {Scroller, ScrollerModule, ScrollerOptions} from 'primeng/scroller';
import {RippleModule} from 'primeng/ripple';
import {AutoFocusModule} from 'primeng/autofocus';

export const DROPDOWN_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -72,7 +73,7 @@ export class DropdownItem {
<div class="p-hidden-accessible">
<input #in [attr.id]="inputId" type="text" readonly (focus)="onInputFocus($event)" aria-haspopup="listbox" [attr.placeholder]="placeholder"
aria-haspopup="listbox" [attr.aria-label]="ariaLabel" [attr.aria-expanded]="false" [attr.aria-labelledby]="ariaLabelledBy" (blur)="onInputBlur($event)" (keydown)="onKeydown($event, true)"
[disabled]="disabled" [attr.tabindex]="tabindex" [attr.autofocus]="autofocus" [attr.aria-activedescendant]="overlayVisible ? labelId : null" role="combobox">
[disabled]="disabled" [attr.tabindex]="tabindex" [pAutoFocus]="autofocus" [attr.aria-activedescendant]="overlayVisible ? labelId : null" role="combobox">
</div>
<span [attr.id]="labelId" [ngClass]="{'p-dropdown-label p-inputtext':true,'p-dropdown-label-empty':(label == null || label.length === 0)}" *ngIf="!editable && (label != null)" [pTooltip]="tooltip" [tooltipPosition]="tooltipPosition" [positionStyle]="tooltipPositionStyle" [tooltipStyleClass]="tooltipStyleClass">
<ng-container *ngIf="!selectedItemTemplate">{{label||'empty'}}</ng-container>
Expand Down Expand Up @@ -1302,7 +1303,7 @@ export class Dropdown implements OnInit,AfterViewInit,AfterContentInit,AfterView
}

@NgModule({
imports: [CommonModule,SharedModule,TooltipModule,RippleModule,ScrollerModule],
imports: [CommonModule,SharedModule,TooltipModule,RippleModule,ScrollerModule, AutoFocusModule],
exports: [Dropdown,SharedModule,ScrollerModule],
declarations: [Dropdown,DropdownItem]
})
Expand Down
5 changes: 3 additions & 2 deletions src/app/components/inputmask/inputmask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {CommonModule} from '@angular/common';
import {DomHandler} from 'primeng/dom';
import {InputTextModule} from 'primeng/inputtext';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
import {AutoFocusModule} from 'primeng/autofocus';

export const INPUTMASK_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
Expand All @@ -42,7 +43,7 @@ export const INPUTMASK_VALUE_ACCESSOR: any = {
template: `
<input #input pInputText class="p-inputmask" [attr.id]="inputId" [attr.type]="type" [attr.name]="name" [ngStyle]="style" [ngClass]="styleClass" [attr.placeholder]="placeholder" [attr.title]="title"
[attr.size]="size" [attr.autocomplete]="autocomplete" [attr.maxlength]="maxlength" [attr.tabindex]="tabindex" [attr.aria-label]="ariaLabel" [attr.aria-required]="ariaRequired" [disabled]="disabled" [readonly]="readonly" [attr.required]="required"
(focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (keydown)="onInputKeydown($event)" (keypress)="onKeyPress($event)" [attr.autofocus]="autoFocus"
(focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (keydown)="onInputKeydown($event)" (keypress)="onKeyPress($event)" [pAutoFocus]="autoFocus"
(input)="onInputChange($event)" (paste)="handleInputChange($event)">
<i *ngIf="value != null && filled && showClear && !disabled" class="p-inputmask-clear-icon pi pi-times" (click)="clear()"></i>
`,
Expand Down Expand Up @@ -666,7 +667,7 @@ export class InputMask implements OnInit,ControlValueAccessor {
}

@NgModule({
imports: [CommonModule,InputTextModule],
imports: [CommonModule,InputTextModule, AutoFocusModule],
exports: [InputMask],
declarations: [InputMask]
})
Expand Down
3 changes: 2 additions & 1 deletion src/app/showcase/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ import { AppMainComponent } from './app.main.component';
{path: 'virtualscroller', loadChildren: () => import('./components/virtualscroller/virtualscrollerdemo.module').then(m => m.VirtualScrollerDemoModule)},
{path: 'accessibility', loadChildren: () => import('./components/accessibility/accessibilitydemo.module').then(m => m.AccessibilityDemoModule)},
{path: 'scroller', loadChildren: () => import('./components/scroller/scrollerdemo.module').then(m => m.ScrollerDemoModule)},
{path: 'uikit', loadChildren: () => import('./components/uikit/uikit.module').then(m => m.UIKitModule)}
{path: 'uikit', loadChildren: () => import('./components/uikit/uikit.module').then(m => m.UIKitModule)},
{path: 'autofocus', loadChildren: () => import('./components/autofocus/autofocusdemo.module').then(m => m.AutoFocusDemoModule)}
],
},
],{scrollPositionRestoration: 'enabled', useHash: false})
Expand Down
1 change: 1 addition & 0 deletions src/app/showcase/app.menu.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ declare let gtag: Function;
<a [routerLink]=" ['focustrap']" routerLinkActive="router-link-exact-active">FocusTrap</a>
<a [routerLink]=" ['styleclass']" routerLinkActive="router-link-exact-active">StyleClass</a>
<a [routerLink]=" ['ripple']" routerLinkActive="router-link-exact-active">Ripple</a>
<a [routerLink]=" ['autofocus']" routerLinkActive="router-link-exact-active">AutoFocus<span class="p-tag">New</span></a>
</div>
<div class="menu-category">Utilities</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AutoFocusDemo } from './autofocusdemo.component';

@NgModule({
imports: [RouterModule.forChild([
{ path: '', component: AutoFocusDemo }
])],
exports: [RouterModule]
})
export class AutoFocusDemoRoutingModule { }
79 changes: 79 additions & 0 deletions src/app/showcase/components/autofocus/autofocusdemo.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<div class="content-section introduction">
<div class="feature-intro">
<h1>AutoFocus</h1>
<p>AutoFocus manages focus on focusable element on load.</p>
</div>
<app-demoActions github="autofocus" stackblitz="autofocus-demo"></app-demoActions>
</div>

<div class="content-section implementation">
<input type="text" pInputText [pAutoFocus]="true" placeholder="Automatically focused" />
</div>

<div class="content-section documentation">
<p-tabView>
<p-tabPanel header="Documentation">
<h5>Import</h5>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;AutoFocusModule&#125; from 'primeng/autofocus';
</app-code>

<h5>Getting Started</h5>
<p>AutoFocus is applied to any focusable input element on initial load. It's disabled by default and needs to be enabled manually.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;input [pAutoFocus]="true" &gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class AutoFocusDemo &#123; &#125;
</app-code>

<h5>Properties</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>pAutoFocus</td>
<td>boolean</td>
<td>null</td>
<td>When present, it specifies that the component should automatically get focus on load.</td>
</tr>
</tbody>
</table>
</div>

<h5>Events</h5>
<p>Directive has no events.</p>

<h5>Styling</h5>
<p>Directive does not apply any styling to host.</p>

<h5>Dependencies</h5>
<p>None.</p>
</p-tabPanel>

<p-tabPanel header="Source">
<a href="https://github.com/primefaces/primeng/tree/master/src/app/showcase/components/autofocus" class="btn-viewsource" target="_blank">
<span>View on GitHub</span>
</a>
<a href="https://stackblitz.com/edit/primeng-autofocus-demo" class="btn-viewsource" style="margin-left: .5em;" target="_blank">
<span>Edit in StackBlitz</span>
</a>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;input type="text" pInputText [pAutoFocus]="true" placeholder="Automatically focused" &gt;
</app-code>

</p-tabPanel>
</p-tabView>
</div>

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Component, OnInit } from '@angular/core';

@Component({
selector: 'autofocusdemo',
templateUrl: './autofocusdemo.component.html'
})
export class AutoFocusDemo {}
26 changes: 26 additions & 0 deletions src/app/showcase/components/autofocus/autofocusdemo.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AppCodeModule } from '../../app.code.component';
import { TabViewModule } from 'primeng/tabview';
import { AutoFocusModule } from 'primeng/autofocus';
import { AppDemoActionsModule } from '../../app.demoactions.component';
import { AutoFocusDemo } from './autofocusdemo.component';
import { AutoFocusDemoRoutingModule } from './autofocusdemo-routing.module';
import { InputTextModule } from 'primeng/inputtext';


@NgModule({
imports: [
CommonModule,
FormsModule,
AppCodeModule,
TabViewModule,
AutoFocusModule,
InputTextModule,
AppDemoActionsModule,
AutoFocusDemoRoutingModule
],
declarations: [AutoFocusDemo],
})
export class AutoFocusDemoModule { }

0 comments on commit 7c6c1e4

Please sign in to comment.