@angular/core#AfterContentInit TypeScript Examples
The following examples show how to use
@angular/core#AfterContentInit.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: accordion.component.ts From canopy with Apache License 2.0 | 6 votes |
@Component({
selector: 'lg-accordion',
templateUrl: './accordion.component.html',
styleUrls: [ './accordion.component.scss' ],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ { provide: LG_ACCORDION, useExisting: LgAccordionComponent } ],
})
export class LgAccordionComponent implements AfterContentInit {
@HostBinding('class.lg-accordion') class = true;
@HostBinding('id') @Input() id = `lg-accordion-${nextUniqueId++}`;
@Input() headingLevel: HeadingLevel;
@Input() multi = true;
@ContentChildren(forwardRef(() => LgAccordionPanelHeadingComponent), {
descendants: true,
})
panelHeadings: QueryList<LgAccordionPanelHeadingComponent>;
ngAfterContentInit() {
this.panelHeadings.forEach(panelHeading => {
panelHeading.headingLevel = this.headingLevel;
});
}
}
Example #2
Source File: ngx-detect-hide-on-scroll.directive.ts From Elastos.Essentials.App with MIT License | 6 votes |
/**
* Use this on scrollable elements to notify [ngxHideOnScroll] on render updates (e.g *ngIfs)
*/
@Directive({ selector: '[ngxDetectHideOnScroll]' })
export class NgxDetectHideOnScrollDirective implements AfterContentInit, OnDestroy {
constructor(private s: NgxHideOnScrollService) {}
ngAfterContentInit() {
// wait a tick to let initted element render
setTimeout(() => this.s.scrollingElementsDetected$.next());
}
ngOnDestroy() {
this.s.scrollingElementsDetected$.next();
}
}
Example #3
Source File: option-group.component.ts From alauda-ui with MIT License | 6 votes |
@Component({
selector: 'aui-option-group',
templateUrl: './option-group.component.html',
styleUrls: ['./option-group.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
})
export class OptionGroupComponent<T> implements AfterContentInit {
@ContentChildren(forwardRef(() => OptionComponent))
options: QueryList<OptionComponent<T>>;
hasVisibleOption$: Observable<boolean>;
ngAfterContentInit() {
this.hasVisibleOption$ = this.options.changes.pipe(
startWith(this.options),
switchMap((options: QueryList<OptionComponent<T>>) =>
options.length > 0
? combineLatest(options.map(node => node.visible$))
: of([false]),
),
map(visible => visible.some(Boolean)),
publishRef(),
);
}
}
Example #4
Source File: focus-key-list.directive.ts From sba-angular with MIT License | 6 votes |
@Directive({
selector: "[sqFocusKeyList]"
})
export class FocusKeyListDirective implements OnChanges, AfterContentInit {
@Input() activeItem = -1;
@Input() withWrap = true;
@Output() itemSelect = new EventEmitter<number>();
@HostBinding("attr.role") role = "list";
@ContentChildren(FocusKeyListItemDirective) components: QueryList<FocusKeyListItemDirective>;
protected keyManager: FocusKeyManager<FocusKeyListItemDirective>;
ngOnChanges() {
if (this.keyManager) {
this.keyManager.setActiveItem(this.activeItem);
}
}
ngAfterContentInit() {
this.keyManager = new FocusKeyManager<FocusKeyListItemDirective>(this.components);
if (this.withWrap) {
this.keyManager.withWrap();
}
if (this.activeItem >= 0 && this.components.length > 0) {
Utils.delay().then(() => {
this.keyManager.setActiveItem(this.activeItem);
});
}
}
@HostListener("keydown", ["$event"])
onKeydown(event) {
this.keyManager.onKeydown(event);
this.itemSelect.emit(this.keyManager.activeItemIndex !== null ? this.keyManager.activeItemIndex : undefined);
}
}
Example #5
Source File: input-group.component.ts From alauda-ui with MIT License | 6 votes |
@Component({
selector: 'aui-input-group',
templateUrl: './input-group.component.html',
styleUrls: ['./input-group.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
})
export class InputGroupComponent implements AfterContentInit {
bem: Bem = buildBem('aui-input-group');
@ContentChildren(InputAddonBeforeDirective)
private readonly addonBeforeRefs: QueryList<InputAddonBeforeDirective>;
@ContentChildren(InputAddonAfterDirective)
private readonly addonAfterRefs: QueryList<InputAddonAfterDirective>;
@ContentChildren(InputPrefixDirective)
private readonly prefixRefs: QueryList<InputPrefixDirective>;
@ContentChildren(InputSuffixDirective)
private readonly suffixRefs: QueryList<InputSuffixDirective>;
@ContentChild(InputComponent, { static: false })
inputRef: InputComponent;
hasAddonBefore$: Observable<boolean>;
hasAddonAfter$: Observable<boolean>;
hasPrefix$: Observable<boolean>;
hasSuffix$: Observable<boolean>;
ngAfterContentInit() {
this.hasAddonBefore$ = watchContentExist(this.addonBeforeRefs);
this.hasAddonAfter$ = watchContentExist(this.addonAfterRefs);
this.hasPrefix$ = watchContentExist(this.prefixRefs);
this.hasSuffix$ = watchContentExist(this.suffixRefs);
}
}
Example #6
Source File: network.component.ts From blockcore-hub with MIT License | 5 votes |
@Component({
selector: 'app-network',
templateUrl: './network.component.html',
styleUrls: ['./network.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class NetworkComponent implements OnInit, OnDestroy, AfterContentInit {
@HostBinding('class.network') hostClass = true;
columns = 4;
gridByBreakpoint = {
xl: 8,
lg: 6,
md: 4,
sm: 2,
xs: 1
};
private mediaObservable;
constructor(
private globalService: GlobalService,
private apiService: ApiService,
private readonly cd: ChangeDetectorRef,
public mediaObserver: MediaObserver,
public router: Router,
public walletService: WalletService) {
}
ngOnInit() {
}
ngAfterContentInit() {
// There is a bug with this, does not always trigger when navigating back and forth, and resizing.
// This means the number of grids sometimes defaults to 4, even though the screen is small.
this.mediaObservable = this.mediaObserver.media$.subscribe((change: MediaChange) => {
this.columns = this.gridByBreakpoint[change.mqAlias];
});
}
ngOnDestroy() {
this.mediaObservable.unsubscribe();
}
details() {
this.router.navigateByUrl('/network/details');
}
}
Example #7
Source File: np-menubar.component.ts From np-ui-lib with MIT License | 5 votes |
@Component({
selector: "np-menubar",
templateUrl: "./np-menubar.component.html",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.Default,
})
export class NpMenubarComponent implements AfterContentInit, OnDestroy {
private static controlCount = 1;
@Input() items: NpMenuItem[];
@Input() orientation: 'horizontal' | 'vertical';
@Input() isPanelMenu: boolean;
@Input() styleClass: string;
@Input() inputId: string = `np-menubar_${NpMenubarComponent.controlCount++}`;
@Output() onClickMenuItem: EventEmitter<any> = new EventEmitter();
subscription: Subscription;
ngAfterContentInit(): void {
if (!this.isPanelMenu) {
this.subscription = this.onClickMenuItem.subscribe(() => {
this.items.forEach((element: NpMenuItem) => {
if (element.items) {
this._collapseMenu(element);
}
});
});
this.orientation = this.orientation ? this.orientation : "vertical";
} else {
this.orientation = null;
}
}
ngOnDestroy(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
_collapseMenu(item: NpMenuItem): void {
item.items.forEach((element: NpMenuItem) => {
if (element.items) {
this._collapseMenu(element);
}
});
item.isChildVisible = false;
}
_onClickMenuItem(item: NpMenuItem): void {
this.onClickMenuItem.emit(item);
}
}
Example #8
Source File: network.component.ts From EXOS-Core with MIT License | 5 votes |
@Component({
selector: 'app-network',
templateUrl: './network.component.html',
styleUrls: ['./network.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class NetworkComponent implements OnInit, OnDestroy, AfterContentInit {
@HostBinding('class.network') hostClass = true;
columns = 4;
gridByBreakpoint = {
xl: 8,
lg: 6,
md: 4,
sm: 2,
xs: 1
};
private mediaObservable;
constructor(
private globalService: GlobalService,
private apiService: ApiService,
private readonly cd: ChangeDetectorRef,
public mediaObserver: MediaObserver,
public router: Router,
public walletService: WalletService,
public localeService: LocaleService) {
}
ngOnInit() {
}
ngAfterContentInit() {
// There is a bug with this, does not always trigger when navigating back and forth, and resizing.
// This means the number of grids sometimes defaults to 4, even though the screen is small.
this.mediaObservable = this.mediaObserver.media$.subscribe((change: MediaChange) => {
this.columns = this.gridByBreakpoint[change.mqAlias];
});
}
ngOnDestroy() {
this.mediaObservable.unsubscribe();
}
details() {
this.router.navigateByUrl('/network-details');
}
}
Example #9
Source File: color-toggle.component.ts From angular-material-components with MIT License | 5 votes |
@Component({
selector: 'ngx-mat-color-toggle',
templateUrl: './color-toggle.component.html',
styleUrls: ['./color-toggle.component.scss'],
host: {
'class': 'ngx-mat-color-toggle',
// Always set the tabindex to -1 so that it doesn't overlap with any custom tabindex the
// consumer may have provided, while still being able to receive focus.
'[attr.tabindex]': '-1',
'[class.ngx-mat-color-toggle-active]': 'picker && picker.opened',
'[class.mat-accent]': 'picker && picker.color === "accent"',
'[class.mat-warn]': 'picker && picker.color === "warn"',
'(focus)': '_button.focus()',
},
exportAs: 'ngxMatColorPickerToggle',
encapsulation: ViewEncapsulation.None
})
export class NgxMatColorToggleComponent implements OnInit, AfterContentInit, OnChanges, OnDestroy {
private _stateChanges = Subscription.EMPTY;
@Input('for') picker: NgxMatColorPickerComponent;
@Input() tabIndex: number;
@Input() get disabled(): boolean {
if (this._disabled == null && this.picker) {
return this.picker.disabled;
}
}
set disabled(value: boolean) {
this._disabled = value;
}
private _disabled: boolean;
@ViewChild('button') _button: MatButton;
constructor(private _cd: ChangeDetectorRef) { }
ngOnInit() {
}
ngOnChanges(changes: SimpleChanges): void {
if (changes['picker']) {
this._watchStateChanges();
}
}
ngOnDestroy() {
this._stateChanges.unsubscribe();
}
ngAfterContentInit() {
this._watchStateChanges();
}
public open(event: Event): void {
if (this.picker && !this.disabled) {
this.picker.open();
event.stopPropagation();
}
}
private _watchStateChanges() {
const disabled$ = this.picker ? this.picker._disabledChange : of();
const inputDisabled$ = this.picker && this.picker._pickerInput ?
this.picker._pickerInput._disabledChange : of();
const pickerToggled$ = this.picker ?
merge(this.picker.openedStream, this.picker.closedStream) : of();
this._stateChanges.unsubscribe();
this._stateChanges = merge(disabled$, inputDisabled$, pickerToggled$).subscribe(() => this._cd.markForCheck());
}
}
Example #10
Source File: validators.ts From alauda-ui with MIT License | 5 votes |
@Directive({
selector:
// eslint-disable-next-line @angular-eslint/directive-selector
'aui-select[ngModel][includes],aui-select[formControl][includes],aui-select[formControlName][includes]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => IncludesDirective),
multi: true,
},
],
})
export class IncludesDirective<T> implements Validator, AfterContentInit {
@Input()
get includes() {
return this._includes;
}
set includes(val: boolean | '') {
this._includes = coerceAttrBoolean(val);
if (this.onValidatorChange) {
this.onValidatorChange();
}
}
@Input()
trackFn: TrackFn<T>;
private _includes = false;
onValidatorChange: () => void;
constructor(private readonly selectRef: SelectComponent<T>) {}
ngAfterContentInit() {
this.selectRef.contentOptions.changes.subscribe(() => {
if (this.onValidatorChange) {
this.onValidatorChange();
}
});
}
registerOnValidatorChange(fn: () => void) {
this.onValidatorChange = fn;
}
validate(control: AbstractControl): ValidationErrors {
if (!this.selectRef.contentOptions || !control.value) {
return;
}
return !this.includes
? null
: AuiSelectValidators.includes(
this.selectRef.contentOptions
.filter(option => !option.disabled)
.map(option => option.value),
this.trackFn,
)(control);
}
}
Example #11
Source File: tutorial-dialog.component.ts From bdc-walkthrough with MIT License | 5 votes |
@Component({
selector: 'bdc-walk-dialog',
templateUrl: './tutorial-dialog.component.html',
styleUrls: ['./tutorial-dialog.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class BdcWalkDialogComponent implements AfterContentInit, OnDestroy, OnChanges {
@Input() name: string;
@Input() mustCompleted: { [taskName: string]: any | boolean } = {};
@Input() mustNotDisplaying: string[] = [];
@Input() width = '500px';
@Output() opened = new EventEmitter<void>();
@Output() closed = new EventEmitter<void>();
@ViewChild(TemplateRef, {static: true}) templateRef: TemplateRef<any>;
dialogRef: MatDialogRef<any>;
componentSubscription: Subscription;
constructor(private dialog: MatDialog,
private tutorialService: BdcWalkService) { }
ngAfterContentInit() {
this.componentSubscription = this.tutorialService.changes.subscribe(() => this._sync());
}
ngOnChanges(): void {
this._sync();
}
ngOnDestroy() {
if (this.componentSubscription) {
this.componentSubscription.unsubscribe();
}
this._close();
}
getValue(taskName: string): any {
return this.tutorialService.getTaskCompleted(taskName);
}
close(setTasks: { [taskName: string]: any | boolean } = {}) {
this.tutorialService.logUserAction(this.name, BdcDisplayEventAction.UserClosed);
this.tutorialService.setTaskCompleted(this.name);
this.tutorialService.setTasks(setTasks);
}
private _open() {
this.dialogRef = this.dialog.open(this.templateRef, {width: this.width, disableClose: true, restoreFocus: false, panelClass: 'bdc-walk-dialog'});
this.opened.emit();
}
private _close() {
if (this.dialogRef) {
this.dialogRef.close();
this.dialogRef = null;
this.closed.emit();
}
}
private _sync() {
if (this.name) {
if (!this.tutorialService.getTaskCompleted(this.name) &&
!this.tutorialService.disabled &&
this.tutorialService.evalMustCompleted(this.mustCompleted) &&
this.tutorialService.evalMustNotDisplaying(this.mustNotDisplaying)) {
if (!this.dialogRef) {
this._open();
this.tutorialService.setIsDisplaying(this.name, true);
}
} else if (this.dialogRef) {
this._close();
this.tutorialService.setIsDisplaying(this.name, false);
}
}
}
}
Example #12
Source File: breadcrumb.component.ts From alauda-ui with MIT License | 5 votes |
@Component({
selector: 'aui-breadcrumb',
templateUrl: './breadcrumb.component.html',
styleUrls: ['./breadcrumb.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
})
export class BreadcrumbComponent implements AfterContentInit {
@Input()
get separator() {
return this._separator;
}
set separator(val) {
if (val === this._separator) {
return;
}
this._separator = val;
if (this.items) {
this.items.forEach(item => {
item.separator = val;
});
}
}
@Input()
get separatorIcon() {
return this._separatorIcon;
}
set separatorIcon(val) {
if (val === this._separatorIcon) {
return;
}
this._separatorIcon = val;
if (this.items) {
this.items.forEach(item => {
item.separatorIcon = val;
});
}
}
@ContentChildren(BreadcrumbItemComponent)
items: QueryList<BreadcrumbItemComponent>;
private _separator = '/';
private _separatorIcon = '';
ngAfterContentInit() {
this.items.forEach(item => {
item.separator = this.separator;
item.separatorIcon = this.separatorIcon;
});
}
}
Example #13
Source File: modal.component.ts From canopy with Apache License 2.0 | 5 votes |
@Component({
selector: 'lg-modal',
templateUrl: './modal.component.html',
styleUrls: [ './modal.component.scss' ],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LgModalComponent implements OnInit, AfterContentInit, OnDestroy {
private subscription: Subscription;
isOpen: boolean;
@Input() id: string;
@Output() open: EventEmitter<void> = new EventEmitter();
@Output() closed: EventEmitter<void> = new EventEmitter();
@ContentChild(forwardRef(() => LgModalHeaderComponent))
modalHeaderComponent: LgModalHeaderComponent;
@ContentChild(forwardRef(() => LgModalBodyComponent))
modalBodyComponent: LgModalBodyComponent;
constructor(private cdr: ChangeDetectorRef, private modalService: LgModalService) {}
@HostListener('keydown', [ '$event' ]) onKeydown(event: KeyboardEvent): void {
if (event.key === keyName.KEY_ESCAPE && this.isOpen) {
this.modalService.close(this.id);
}
}
// onOverlayClick and onModalClick add the following functionality:
// clicking outside the modal closes the modal unless specified
// otherwise using closeOnOverlayClick.
// We specifically listen to the `mousedown` event because with
// the `click` event a user could click inside the modal and
// drag the mouse on the overlay causing the modal to close.
@HostListener('mousedown') onOverlayClick(): void {
this.modalService.close(this.id);
}
ngOnInit(): void {
this.subscription = this.modalService
.isOpen$(this.id)
.pipe(
map(isOpen => {
this.isOpen = isOpen;
const bodyEl: HTMLBodyElement = document.querySelector('body');
if (isOpen) {
bodyEl.style.overflow = 'hidden';
this.open.emit();
} else {
this.closed.emit();
bodyEl.style.overflow = '';
}
this.cdr.detectChanges();
}),
)
.subscribe();
}
ngAfterContentInit(): void {
this.modalHeaderComponent.id = `lg-modal-header-${this.id}`;
this.modalHeaderComponent.modalId = this.id;
this.modalBodyComponent.id = `lg-modal-body-${this.id}`;
}
onModalClick(event: Event): void {
event.stopPropagation();
}
ngOnDestroy(): void {
this.modalService.remove(this.id);
this.subscription.unsubscribe();
}
}
Example #14
Source File: autofocus.directive.ts From jira-clone-angular with MIT License | 5 votes |
@Directive({
selector: '[jAutofocus]'
})
export class AutofocusDirective implements AfterContentInit, OnDestroy {
@Input('jAutofocus') enable: boolean | string;
@Input() timerDelay: number = BASE_TIMER_DELAY;
private elementRef: ElementRef;
private timer: any;
constructor(elementRef: ElementRef) {
this.elementRef = elementRef;
this.timer = null;
}
public ngAfterContentInit(): void {
this.setDefaultValue();
if (this.enable) {
this.startFocusWorkflow();
}
}
public ngOnDestroy(): void {
this.stopFocusWorkflow();
}
private setDefaultValue() {
if (this.enable === false) {
return;
}
this.enable = true;
}
private startFocusWorkflow(): void {
if (this.timer) {
return;
}
this.timer = setTimeout((): void => {
this.timer = null;
this.elementRef.nativeElement.focus();
}, this.timerDelay);
}
private stopFocusWorkflow(): void {
clearTimeout(this.timer);
this.timer = null;
}
}
Example #15
Source File: np-data-grid.component.ts From np-ui-lib with MIT License | 4 votes |
@Component({
selector: "np-data-grid",
templateUrl: "np-data-grid.component.html",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.Default,
})
export class NpDataGridComponent
implements OnInit, AfterContentInit, AfterViewInit, OnDestroy {
private static controlCount = 1;
@Input() inputId: string = `np-data-grid_${NpDataGridComponent.controlCount++}`;
@Input() columns: Column[];
@Input() dataSource: BehaviorSubject<DataSource>;
@Input() height: number;
@Input() width: number;
@Input() multiColumnSortEnable: boolean;
@Input() masterDetailTemplate: TemplateRef<any>;
@Input() singleRowExpand: boolean = false;
@Input() expandRowOnClick: boolean = false;
@Input() singleRowSelectEnable: boolean = false;
@Input() multiRowSelectEnable: boolean = false;
@Input() selectRowOnClick: boolean = false;
@Input() key: string;
@Input() showColumnChooser: boolean;
@Input() title: string = "";
@Input() enableStateStoring: boolean;
@Input() isReadOnlyStates: boolean = false;
@Input() noDataMessage: string;
@Input() showFilters = true;
@Input() dateFormat = "dd/MM/yyyy";
@Input() showSummary: boolean = false;
@Input() summaryTemplate: TemplateRef<any>;
@Input() allowColumnResize: boolean = false;
@Input() allowColumnReorder: boolean = false;
@Input() isServerOperations: boolean = false;
@Input() isODataOperations: boolean = false;
@Input() allowExport: boolean = false;
@Input() isServerExport: boolean = false;
@Input() showToolBar: boolean = false;
@Input() pageSize: number = 10;
@Input() styleClass: string;
@Output() onInit: EventEmitter<any> = new EventEmitter();
@Output() onAfterInit: EventEmitter<any> = new EventEmitter();
@Output() onLoadData: EventEmitter<LoadOptions> = new EventEmitter();
@Output() onSelect: EventEmitter<any> = new EventEmitter();
@Output() onDeselect: EventEmitter<any> = new EventEmitter();
@Output() onRowClick: EventEmitter<any> = new EventEmitter();
@Output() onStatesUpdate: EventEmitter<any> = new EventEmitter();
@Output() onServerExport: EventEmitter<LoadOptions> = new EventEmitter();
@ViewChild("columnChooserTemplate") columnChooserTemplate: TemplateRef<any>;
@ViewChild("gridPaginator") gridPaginator: NpPaginatorComponent;
gridColumns: Column[];
dataSourceClone: DataSource;
subscription: Subscription;
currentViewData: any[];
totalRow: number = 0;
filtersList: any[];
sortColumnList: any[];
filterColumnList: any[];
isFilterAvailable: boolean;
enableMasterDetail: boolean = false;
openRowKeys: any[] = [];
selectedRowKeys: any[] = [];
isAllSelected: boolean;
keyColumnName: string;
dataTypes = DataTypes;
sortDirections = SortDirections;
isOpenColumnChooser: boolean = false;
visibleColumns: any[] = [];
stateList: State[];
currentStateName: string;
summaryData: any;
searchColumnsKeyword: string;
isDataSourceInit: boolean = false;
_colSpanForDetailRow: number = 0;
private columnChooserTemplatePortal: TemplatePortal<any>;
private columnChooserOverlayRef: OverlayRef;
constructor(
private filterService: NpFilterService,
private utilityService: NpGridUtilityService,
private oDataService: NpODataService,
private fileService: NpFileService,
public overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private overlayPositionBuilder: OverlayPositionBuilder,
private dialogService: NpDialogService,
private translationsService: NpTranslationsService,
private elementRef: ElementRef
) {
this.sortColumnList = [];
this.filtersList = Filters;
this.filterColumnList = [];
this.stateList = [];
this.currentStateName = "";
this.isFilterAvailable = false;
this.showFilters = true;
}
ngOnInit(): void {
this.onInit.emit();
}
ngAfterContentInit(): void {
if (this.masterDetailTemplate) {
this.enableMasterDetail = true;
}
this._setColumns();
if (this.key) {
this.keyColumnName = this.key;
} else {
this.keyColumnName = this.gridColumns[0].dataField;
}
this._subscribeDataSource();
}
ngAfterViewInit(): void {
const positionStrategy = this.overlayPositionBuilder
.flexibleConnectedTo(
this.elementRef.nativeElement.querySelector("#btn-column-chooser")
)
.withPositions(TopBottomOverlayPositions);
this.columnChooserOverlayRef = this.overlay.create({
positionStrategy,
hasBackdrop: true,
backdropClass: "np-grid-backdrop",
scrollStrategy: this.overlay.scrollStrategies.reposition(),
});
this.columnChooserTemplatePortal = new TemplatePortal(
this.columnChooserTemplate,
this.viewContainerRef
);
this.columnChooserOverlayRef
.backdropClick()
.subscribe(() => this._closeColumnChooser());
this.onAfterInit.emit();
}
ngOnDestroy(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
getSelectedRowKeys(): any[] {
return this.selectedRowKeys;
}
selectRowByKey(key: any): void {
if (this.selectedRowKeys.indexOf(key) === -1) {
this.selectedRowKeys.push(key);
}
}
deselectRowByKey(key: any): void {
const idx = this.selectedRowKeys.indexOf(key);
if (idx >= 0) {
this.selectedRowKeys.splice(idx, 1);
}
}
reset(): void {
this._setColumns();
this.filterColumnList = [];
this.sortColumnList = [];
this.selectedRowKeys = [];
this.openRowKeys = [];
this.isAllSelected = false;
this.isOpenColumnChooser = false;
this.currentStateName = "";
this._closeColumnChooser();
if (this.isServerOperations) {
this.gridPaginator.loadPage(1);
} else {
this._resetDataSource();
this.gridPaginator.loadPage(1);
}
}
selectAll(): void {
this._selectAll();
}
deselectAll(): void {
this._deselectAll();
}
hideColumnByIndex(idx: number): void {
this.gridColumns[idx].visible = false;
this._setVisibleColumns();
}
showColumnByIndex(idx: number): void {
this.gridColumns[idx].visible = true;
this._setVisibleColumns();
}
hideColumnByDataField(dataField: string): void {
for (const element of this.gridColumns) {
if (element.dataField === dataField) {
element.visible = false;
}
}
this._setVisibleColumns();
}
showColumnByDataField(dataField: string): void {
for (const element of this.gridColumns) {
if (element.dataField === dataField) {
element.visible = true;
}
}
this._setVisibleColumns();
}
goToPage(pageNumber: number): void {
this.gridPaginator.loadPage(pageNumber);
}
sortByColumn(dataField: string, direction: SortDirections): void {
const sortColumn = this.utilityService.custFind(
this.gridColumns,
(element: Column) => {
return element.dataField === dataField;
}
);
sortColumn.sortDirection = direction;
this._onSort(sortColumn);
}
filterByColumn(dataField: string, keyword: string, type: FilterTypes): void {
const filterColumn = this.utilityService.custFind(
this.gridColumns,
(element: Column) => {
return element.dataField === dataField;
}
);
filterColumn.filterString = keyword;
filterColumn.filterType = type;
this._onFilter(filterColumn, true);
}
getTotalRows(): number {
return this.totalRow;
}
getCurrentPageNumber(): number {
return this.gridPaginator.currentPage;
}
getPageSize(): number {
return this.pageSize;
}
getTotalPages(): number {
return this.gridPaginator.totalPages;
}
closeAllChild(): void {
this.openRowKeys = [];
}
getFilterColumns(): any[] {
return this.filterColumnList;
}
getSortColumns(): any[] {
return this.sortColumnList;
}
getColumns(): Column[] {
return this._cloneColumns(this.gridColumns);
}
setColumns(columns: Column[]): void {
this.gridColumns = this._cloneColumns(columns);
const currentFilterColumnList = [];
for (const element of this.gridColumns) {
if (
element.filterOperator &&
element.filterValue &&
element.filterValue.toString().length > 0
) {
currentFilterColumnList.push({
dataField: element.dataField,
filterOperator: element.filterOperator,
filterValue: element.filterValue,
dataType: element.dataType,
});
}
}
this.filterColumnList = currentFilterColumnList;
const currentSortColumnList = [];
for (const element of this.gridColumns) {
if (element.sortEnable && element.sortDirection) {
currentSortColumnList.push({
dataField: element.dataField,
sortDirection: element.sortDirection,
});
}
}
this.sortColumnList = currentSortColumnList;
if (!this.isServerOperations) {
this._filterDataSource();
this._sortDataSource();
}
this.gridPaginator.loadPage(1);
this._setVisibleColumns();
this.selectedRowKeys = [];
this.openRowKeys = [];
}
loadStateByName(stateName: string): void {
const state = this.stateList.filter((element: State) => element.name === stateName);
if (state && state.length > 0) {
this.currentStateName = stateName;
this.setColumns(state[0].columns);
} else {
throw new Error("Data grid State not found");
}
}
getCurrentStateName(): string {
return this.currentStateName;
}
removeAllSorting(): void {
this._removeAllSorting();
this.gridPaginator.loadPage(1);
}
removeAllFilters(): void {
this._removeAllFilters();
this.gridPaginator.loadPage(1);
}
getAllState(): State[] {
return this.stateList;
}
setAllState(states: State[]): void {
this.stateList = states;
}
refresh(): void {
this._onRefresh();
}
_subscribeDataSource(): void {
this.subscription = this.dataSource.subscribe((ds: DataSource) => {
if (ds === undefined || ds === null) {
return;
}
if (this.isServerOperations) {
// to export to csv, this change has all data
if (ds.isAllPages) {
this.fileService.downloadCSVFile(
ds.data,
this.visibleColumns,
this.dateFormat
);
return;
}
this.currentViewData = ds.data;
this.summaryData = ds.summary;
this.totalRow = ds.total;
if (this.isAllSelected) {
for (const element of this.currentViewData) {
if (
this.selectedRowKeys.indexOf(element[this.keyColumnName]) === -1
) {
this.selectedRowKeys.push(element[this.keyColumnName]);
}
}
}
} else {
this.dataSourceClone = new DataSource(
ds.data,
ds.data.length,
ds.summary
);
this.totalRow = ds.data.length;
this.summaryData = ds.summary;
this.isDataSourceInit = true;
this.gridPaginator.refresh();
}
});
}
_onPageChange(options: any): void {
if (this.isServerOperations) {
const loadOpt = new LoadOptions();
if (this.isODataOperations) {
const top = options.pageSize;
const skip = (options.currentPage - 1) * options.pageSize;
loadOpt.odataQuery = this.oDataService.buildQuery(
top,
skip,
this.sortColumnList,
this.filterColumnList
);
loadOpt.pageNumber = 0;
loadOpt.pageSize = 0;
loadOpt.sortColumns = [];
loadOpt.filterColumns = [];
loadOpt.isAllPages = false;
} else {
loadOpt.pageNumber = options.currentPage;
loadOpt.pageSize = options.pageSize;
loadOpt.sortColumns = this.sortColumnList;
loadOpt.filterColumns = this.filterColumnList;
loadOpt.isAllPages = false;
loadOpt.odataQuery = "";
}
this.onLoadData.emit(loadOpt);
} else {
if (!this.isDataSourceInit) {
return;
}
const start = (options.currentPage - 1) * options.pageSize;
const end = Math.min(start + options.pageSize - 1, this.totalRow - 1);
this.currentViewData = this.dataSourceClone.data.slice(start, end + 1);
}
}
_setColumns(): void {
const result = [];
for (const element of this.columns) {
result.push(new Column(element));
}
this.gridColumns = result;
this._setVisibleColumns();
}
_setVisibleColumns(): void {
this.visibleColumns = this.utilityService.custFilter(
this.gridColumns,
(element: Column) => element.visible === true
);
this.isFilterAvailable =
this.utilityService.custFilter(this.visibleColumns, (element: Column) => element.filterEnable === true).length > 0;
this._colSpanForDetailRow =
this.visibleColumns.length + (this._allowRowSelection() ? 1 : 0) + 1;
}
_onCellClick($event: any, column: Column, data: any): void {
if (column.onCellClick !== undefined) {
column.onCellClick($event, column, data);
}
}
// on first click ascending, on second click descending and on third click remove sorting
_onSort(column: Column): void {
if (!column.sortEnable) {
return;
}
// if sort direction is descending then remove sorting from column
if (column.sortDirection === SortDirections.Descending) {
this._removeSortingFromColumn(column);
return;
}
const sortOrder =
column.sortDirection === SortDirections.Ascending
? SortDirections.Descending
: SortDirections.Ascending;
if (!this.multiColumnSortEnable) {
this._removeAllSorting();
}
column.sortDirection = sortOrder;
if (this.multiColumnSortEnable) {
const list = [];
for (const element of this.sortColumnList) {
if (element.dataField !== column.dataField) {
list.push(element);
}
}
this.sortColumnList = list;
}
this.sortColumnList.push({
dataField: column.dataField,
sortDirection: column.sortDirection,
});
this.selectedRowKeys = [];
this.isAllSelected = false;
this.openRowKeys = [];
if (!this.isServerOperations) {
this._sortDataSource();
}
this.gridPaginator.loadPage(1);
}
_sortDataSource(): void {
let data = this.dataSourceClone.data;
for (const element of this.sortColumnList) {
data = this.utilityService.custSort(
data,
element.dataField,
element.sortDirection
);
}
this.dataSourceClone.data = data;
}
_removeAllSorting(): void {
for (const element of this.gridColumns) {
element.sortDirection = null;
}
this.sortColumnList = [];
}
_removeSortingFromColumn(column: Column): void {
column.sortDirection = null;
const list = [];
for (const element of this.sortColumnList) {
if (element.dataField !== column.dataField) {
list.push(element);
}
}
this.sortColumnList = list;
if (!this.isServerOperations) {
this._resetDataSource();
this._filterDataSource();
for (const element of this.sortColumnList) {
this.dataSourceClone.data = this.utilityService.custSort(
this.dataSourceClone.data,
element.dataField,
element.sortDirection
);
}
}
this.gridPaginator.loadPage(1);
}
_resetDataSource(): void {
this.dataSourceClone.data = this.dataSource.getValue().data;
this.totalRow = this.dataSourceClone.data.length;
}
_onFilter(column: Column, isForceFilter: boolean = false): void {
if (column.filterOperator && column.filterOperator === FilterTypes.Reset) {
column.filterOperator = undefined;
column.filterValue = undefined;
isForceFilter = true;
}
if (
!isForceFilter &&
(column.filterValue === undefined ||
column.filterValue === null ||
column.filterValue.length === 0 ||
column.filterOperator === undefined ||
column.filterOperator === null)
) {
return;
}
const currentFilterList = [];
for (const element of this.gridColumns) {
if (
element.filterOperator === undefined ||
element.filterOperator === null ||
element.filterValue === undefined ||
element.filterValue === null ||
element.filterValue.toString().length === 0
) {
continue;
} else {
currentFilterList.push({
dataField: element.dataField,
filterOperator: element.filterOperator,
filterValue: element.filterValue,
dataType: element.dataType,
});
}
}
this.filterColumnList = currentFilterList;
this.selectedRowKeys = [];
this.isAllSelected = false;
this.openRowKeys = [];
if (!this.isServerOperations) {
this._filterDataSource();
this._sortDataSource();
}
this.gridPaginator.loadPage(1);
}
_filterDataSource(): void {
const data = this.filterService.filterData(
this.filterColumnList,
this.dataSource.getValue().data
);
this.dataSourceClone.data = data;
this.totalRow = data.length;
}
_removeAllFilters(): void {
for (const element of this.gridColumns) {
element.filterOperator = null;
element.filterValue = null;
}
this.filterColumnList = [];
}
_onClickExpandRow(data: any): void {
if (this.expandRowOnClick === true) {
return;
}
const keyValue = data[this.keyColumnName];
this._expandRow(keyValue);
}
_expandRow(keyValue: any): void {
if (this.singleRowExpand === true) {
this.openRowKeys = [keyValue];
} else {
this.openRowKeys.push(keyValue);
}
}
_onClickCollapseRow(data: any): void {
if (this.expandRowOnClick === true) {
return;
}
const keyValue = data[this.keyColumnName];
this._collapseRow(keyValue);
}
_collapseRow(keyValue: any): void {
const idx = this.openRowKeys.indexOf(keyValue);
this.openRowKeys.splice(idx, 1);
}
_onClickSelectAll(checked: boolean): void {
if (this.singleRowSelectEnable) {
return;
}
if (checked) {
this._selectAll();
} else {
this._deselectAll();
}
}
_deselectAll(): void {
const selectedRows = this.selectedRowKeys;
this.selectedRowKeys = [];
this.isAllSelected = false;
if (this.onDeselect !== undefined) {
const event = { data: selectedRows };
this.onDeselect.emit(event);
}
}
_selectAll(): void {
const key = this.keyColumnName;
const selectedKeys = [];
if (this.isServerOperations) {
for (const element of this.currentViewData) {
selectedKeys.push(element[key]);
}
} else {
for (const element of this.dataSourceClone.data) {
selectedKeys.push(element[key]);
}
}
this.selectedRowKeys = selectedKeys;
this.isAllSelected = true;
if (this.onSelect !== undefined) {
const event = { data: selectedKeys };
this.onSelect.emit(event);
}
}
_onClickSelectRow(checked: boolean, data: any): void {
if (this.selectRowOnClick === true) {
return;
}
const keyValue = data[this.keyColumnName];
this._selectRow(keyValue, checked);
}
_selectRow(keyValue: any, checked: boolean): void {
if (this.singleRowSelectEnable) {
this.selectedRowKeys = [];
if (checked) {
this.selectedRowKeys.push(keyValue);
}
} else {
if (checked) {
this.selectedRowKeys.push(keyValue);
} else {
const idx = this.selectedRowKeys.indexOf(keyValue);
this.selectedRowKeys.splice(idx, 1);
}
}
if (checked) {
if (this.onSelect !== undefined) {
this.onSelect.emit(keyValue);
}
} else {
this.isAllSelected = false;
if (this.onDeselect !== undefined) {
this.onDeselect.emit(keyValue);
}
}
}
_isSelected(data: any): boolean {
const keyValue = data[this.keyColumnName];
return this.selectedRowKeys.indexOf(keyValue) > -1;
}
_isOpenDetailRow(data: any): boolean {
if (!this.enableMasterDetail) {
return false;
}
const keyValue = data[this.keyColumnName];
return this.openRowKeys.indexOf(keyValue) > -1;
}
_rowClick(event: any, data: any): void {
if (this.masterDetailTemplate && this.expandRowOnClick) {
if (this._isOpenDetailRow(data)) {
this._collapseRow(data[this.keyColumnName]);
} else {
this._expandRow(data[this.keyColumnName]);
}
}
if (
(this.singleRowSelectEnable || this.multiRowSelectEnable) &&
this.selectRowOnClick
) {
if (this._isSelected(data)) {
this._selectRow(data[this.keyColumnName], false);
} else {
this._selectRow(data[this.keyColumnName], true);
}
}
if (this.onRowClick) {
event.data = data;
this.onRowClick.emit(event);
}
}
_onColumnChoosing(checked: boolean, col: Column): void {
col.visible = checked;
this._setVisibleColumns();
}
_openColumnChooser(): void {
if (!this.columnChooserOverlayRef.hasAttached()) {
this.columnChooserOverlayRef.attach(this.columnChooserTemplatePortal);
}
}
_closeColumnChooser(): void {
this.columnChooserOverlayRef.detach();
}
_dropColumn(event: CdkDragDrop<string[]>): void {
moveItemInArray(this.gridColumns, event.previousIndex, event.currentIndex);
this._setVisibleColumns();
}
_saveState(): void {
const columns = this._cloneColumns(this.gridColumns);
const currentStateName = this.currentStateName;
let editedState;
for (const element of this.stateList) {
if (element.name === currentStateName) {
element.columns = columns;
editedState = element;
this.dialogService.open(
this.translationsService.translate("Saved_Successfully"),
new NpDialogConfig({ type: "alert" }),
null
);
}
}
if (this.onStatesUpdate) {
this.onStatesUpdate.emit({ action: "edit", state: editedState });
}
}
_openDialogAddNewState(): void {
const promptAddNewState = this.dialogService.open(
this.translationsService.translate("Add_New_State"),
new NpDialogConfig({ type: "prompt" }),
null
);
promptAddNewState.onClose.subscribe((data) => {
if (data != undefined && data != null && data.trim().length > 0) {
this._addState(data);
}
});
}
_addState(stateName: string): void {
const name = stateName.trim();
const state = this.stateList.filter((element: State) => element.name === name);
if (state && state.length > 0) {
this.dialogService.open(
this.translationsService.translate("State_Name_Already_Exists"),
new NpDialogConfig({ type: "alert" }),
null
);
return;
}
const columns = this._cloneColumns(this.gridColumns);
const newState = new State(name, columns);
this.stateList.push(newState);
this.currentStateName = name;
if (this.onStatesUpdate) {
this.onStatesUpdate.emit({ action: "add", state: newState });
}
}
_deleteState(): void {
const currentStateName = this.currentStateName;
const list = [];
let deletedState;
for (const element of this.stateList) {
if (element.name !== currentStateName) {
list.push(element);
} else {
deletedState = element;
}
}
this.stateList = list;
if (this.stateList.length > 0) {
this.currentStateName = this.stateList[0].name;
} else {
this.currentStateName = "";
}
this._loadState();
if (this.onStatesUpdate) {
this.onStatesUpdate.emit({ action: "delete", state: deletedState });
}
this.dialogService.open(
this.translationsService.translate("Deleted_Successfully"),
new NpDialogConfig({ type: "alert" }),
null
);
}
_loadState(): void {
const currentStateName = this.currentStateName;
if (currentStateName === "") {
this.reset();
return;
}
this.loadStateByName(currentStateName);
}
_cloneColumns(cols: Column[]): Column[] {
const result: Column[] = [];
for (const element of cols) {
result.push(new Column(element));
}
return result;
}
_onRefresh(): void {
this.gridPaginator.refresh();
}
_onResetColumns(): void {
this.reset();
}
_resizeColumn($event: any, column: Column): void {
let currentWidth = column.width;
if (isNaN(currentWidth)) {
currentWidth =
$event.source.element.nativeElement.parentElement.offsetWidth;
}
column.width = (isNaN(currentWidth) ? 0 : currentWidth) + $event.distance.x;
$event.source.reset();
}
_exportToFile(): void {
const loadOpt = new LoadOptions();
if (this.isServerExport) {
if (this.isODataOperations) {
loadOpt.odataQuery = this.oDataService.buildQuery(
0,
0,
this.sortColumnList,
this.filterColumnList,
"allpages"
);
loadOpt.isAllPages = true;
} else {
loadOpt.pageNumber = 1;
loadOpt.pageSize = this.totalRow;
loadOpt.sortColumns = this.sortColumnList;
loadOpt.filterColumns = this.filterColumnList;
loadOpt.isAllPages = true;
}
this.onServerExport.emit(loadOpt);
return;
}
if (this.isServerOperations) {
if (this.isODataOperations) {
loadOpt.odataQuery = this.oDataService.buildQuery(
0,
0,
this.sortColumnList,
this.filterColumnList,
"allpages"
);
loadOpt.isAllPages = true;
} else {
loadOpt.pageNumber = 1;
loadOpt.pageSize = this.totalRow;
loadOpt.sortColumns = this.sortColumnList;
loadOpt.filterColumns = this.filterColumnList;
loadOpt.isAllPages = true;
}
this.onLoadData.emit(loadOpt);
} else {
this.fileService.downloadCSVFile(
this.dataSourceClone.data,
this.visibleColumns,
this.dateFormat
);
}
}
_showAllColumns(): void {
this.gridColumns.forEach((element: Column) => {
element.visible = true;
});
this._setVisibleColumns();
}
_clearColumnSearch(): void {
this.searchColumnsKeyword = null;
}
_allowRowSelection(): boolean {
return this.singleRowSelectEnable || this.multiRowSelectEnable;
}
_trackBy(index: number): number {
return index;
}
_isAnyRowSelected(): boolean {
return (
!this.isAllSelected &&
this.selectedRowKeys &&
this.selectedRowKeys.length > 0
);
}
_onClickCheckbox($event: any): void {
if (this.selectRowOnClick) {
$event.preventDefault();
}
}
}
Example #16
Source File: pager-items-comp.ts From ui-pager with Apache License 2.0 | 4 votes |
@Component({
template: ''
})
export abstract class TemplatedItemsComponent implements DoCheck, OnDestroy, AfterContentInit {
public abstract get nativeElement(): Pager;
protected templatedItemsView: Pager;
protected _items: any;
protected _differ: IterableDiffer<KeyedTemplate>;
protected _templateMap: Map<string, KeyedTemplate>;
private _selectedIndex: number;
@ViewChild('loader', { read: ViewContainerRef, static: false }) loader: ViewContainerRef;
@Output()
public setupItemView = new EventEmitter<SetupItemViewArgs>();
@ContentChild(TemplateRef, { static: false }) itemTemplateQuery: TemplateRef<ItemContext>;
itemTemplate: TemplateRef<ItemContext>;
@Input()
get items() {
return this._items;
}
set items(value: any) {
this._items = value;
let needDiffer = true;
if (value instanceof ObservableArray) {
needDiffer = false;
}
if (needDiffer && !this._differ && isListLikeIterable(value)) {
this._differ = this._iterableDiffers.find(this._items).create((_index, item) => item);
}
this.templatedItemsView.items = this._items;
}
@Input()
get selectedIndex(): number {
return this._selectedIndex;
}
set selectedIndex(value) {
this._selectedIndex = value;
this.templatedItemsView.selectedIndex = this._selectedIndex;
}
ngAfterViewInit() {
if (!!this._selectedIndex) {
setTimeout(() => {
if (isIOS) {
this.templatedItemsView.scrollToIndexAnimated(this._selectedIndex, false);
}
this.templatedItemsView.selectedIndex = this._selectedIndex;
});
}
}
constructor(_elementRef: ElementRef, private _iterableDiffers: IterableDiffers) {
this.templatedItemsView = _elementRef.nativeElement;
this.templatedItemsView.on('itemLoading', this.onItemLoading, this);
this.templatedItemsView.on('itemDisposing', this.onItemDisposing, this);
}
ngAfterContentInit() {
if (Trace.isEnabled()) {
PagerLog('TemplatedItemsView.ngAfterContentInit()');
}
this.setItemTemplates();
}
ngOnDestroy() {
this.templatedItemsView.off('itemLoading', this.onItemLoading, this);
this.templatedItemsView.off('itemDisposing', this.onItemDisposing, this);
}
private setItemTemplates() {
if (!this.items) return;
// The itemTemplateQuery may be changed after list items are added that contain <template> inside,
// so cache and use only the original template to avoid errors.
this.itemTemplate = this.itemTemplateQuery;
if (this._templateMap) {
if (Trace.isEnabled()) {
PagerLog('Setting templates');
}
const templates: KeyedTemplate[] = [];
this._templateMap.forEach((value) => {
templates.push(value);
});
this.templatedItemsView.itemTemplates = templates;
}
}
public registerTemplate(key: string, template: TemplateRef<ItemContext>) {
if (Trace.isEnabled()) {
PagerLog(`registerTemplate for key: ${key}`);
}
if (!this._templateMap) {
this._templateMap = new Map<string, KeyedTemplate>();
}
const keyedTemplate = {
key,
createView: this.getItemTemplateViewFactory(template)
};
this._templateMap.set(key, keyedTemplate);
}
@profile
public onItemLoading(args: ItemEventData) {
if (!args.view && !this.itemTemplate) {
return;
}
if (!this.items) return;
const index = args.index;
const items = (args.object as any).items;
const currentItem = typeof items.getItem === 'function' ? items.getItem(index) : items[index];
let viewRef: EmbeddedViewRef<ItemContext>;
if (args.view) {
if (Trace.isEnabled()) {
PagerLog(`onItemLoading: ${index} - Reusing existing view`);
}
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
if (!viewRef && Trace.isEnabled()) {
PagerError(`ViewReference not found for item ${index}. View recycling is not working`);
}
}
if (!viewRef) {
if (Trace.isEnabled()) {
PagerLog(`onItemLoading: ${index} - Creating view from template`);
}
viewRef = this.loader.createEmbeddedView(this.itemTemplate, new ItemContext(), 0);
args.view = getItemViewRoot(viewRef);
args.view[NG_VIEW] = viewRef;
}
this.setupViewRef(viewRef, currentItem, index);
this.detectChangesOnChild(viewRef, index);
}
@profile
public onItemDisposing(args: ItemEventData) {
if (!args.view) {
return;
}
let viewRef: EmbeddedViewRef<ItemContext>;
if (args.view) {
if (Trace.isEnabled()) {
PagerLog(`onItemDisposing: ${args.index} - Removing angular view`);
}
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
if (!viewRef && Trace.isEnabled()) {
PagerError(`ViewReference not found for item ${args.index}. View disposing is not working`);
}
}
if (viewRef) {
if (Trace.isEnabled()) {
PagerLog(`onItemDisposing: ${args.index} - Disposing view reference`);
}
viewRef.destroy();
}
}
public setupViewRef(viewRef: EmbeddedViewRef<ItemContext>, data: any, index: number): void {
const context = viewRef.context;
context.$implicit = data;
context.item = data;
context.index = index;
context.even = index % 2 === 0;
context.odd = !context.even;
this.setupItemView.next({
view: viewRef,
data,
index,
context
});
}
protected getItemTemplateViewFactory(template: TemplateRef<ItemContext>): () => View {
return () => {
const viewRef = this.loader.createEmbeddedView(template, new ItemContext(), 0);
const resultView = getItemViewRoot(viewRef);
resultView[NG_VIEW] = viewRef;
return resultView;
};
}
@profile
private detectChangesOnChild(viewRef: EmbeddedViewRef<ItemContext>, index: number) {
if (Trace.isEnabled()) {
PagerLog(`Manually detect changes in child: ${index}`);
}
viewRef.markForCheck();
viewRef.detectChanges();
}
ngDoCheck() {
if (this._differ) {
if (Trace.isEnabled()) {
PagerLog('ngDoCheck() - execute differ');
}
const changes = this._differ.diff(this._items);
if (changes) {
if (Trace.isEnabled()) {
PagerLog('ngDoCheck() - refresh');
}
this.templatedItemsView.refresh();
}
}
}
}
Example #17
Source File: np-color-picker.component.ts From np-ui-lib with MIT License | 4 votes |
@Component({
selector: "np-color-picker",
templateUrl: "np-color-picker.component.html",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.Default,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NpColorPickerComponent),
multi: true,
},
],
})
export class NpColorPickerComponent
implements ControlValueAccessor, AfterViewInit, AfterContentInit {
private static controlCount = 1;
/* forma can be 'hex' or 'rgb' */
@Input() format: string = "hex";
@Input() colors: string[];
@Input() defaultOpen: boolean;
@Input() readOnly: boolean;
@Input() autoFocus: boolean;
@Input() tabIndex: number;
@Input() styleClass: string;
@Input() inputId: string = `np-color-picker_${NpColorPickerComponent.controlCount++}`;
@Output() onChange: EventEmitter<any> = new EventEmitter();
@Output() onFocus: EventEmitter<any> = new EventEmitter();
@Output() onBlur: EventEmitter<any> = new EventEmitter();
@ViewChild("templatePortalContent") templatePortalContent: TemplateRef<any>;
@ViewChild("control") inputViewChild: ElementRef;
constructor(
public overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private overlayPositionBuilder: OverlayPositionBuilder,
private elementRef: ElementRef
) { }
isOpen: boolean = false;
stripColor: string;
currentCursorColor: string;
xColorCursor: string;
yColorCursor: string;
innerValue: string;
isDisabled: boolean = false;
currentHex: string = "";
currentR: number;
currentG: number;
currentB: number;
focused: boolean = false;
private templatePortal: TemplatePortal<any>;
private overlayRef: OverlayRef;
private onChangeCallback: (_: any) => void = () => { };
private onTouchedCallback: () => void = () => { };
ngAfterContentInit(): void {
if (!this.colors) {
if (this.format === "hex") {
this.colors = [
"#FF0000",
"#FF7F00",
"#FFFF00",
"#7FFF00",
"#00FF00",
"#00FF7F",
"#00FFFF",
"#007FFF",
"#0000FF",
"#7F00FF",
"#FF00FF",
"#FF007F",
"#f44336",
"#e91e63",
"#9c27b0",
"#673ab7",
"#3f51b5",
"#2196f3",
"#03a9f4",
"#00bcd4",
"#009688",
"#4caf50",
"#8bc34a",
"#cddc39",
"#ffeb3b",
"#ffc107",
"#ff9800",
"#ff5722",
"#795548",
"#9e9e9e",
"#607d8b",
"#000000",
];
} else {
this.colors = [
"rgb(255,0,0)",
"rgb(255,127,0)",
"rgb(255,255,0)",
"rgb(127,255,0)",
"rgb(0,255,0)",
"rgb(0,255,127)",
"rgb(0,255,255)",
"rgb(0,127,255)",
"rgb(0,0,255)",
"rgb(127,0,255)",
"rgb(255,0,255)",
"rgb(255,0,127)",
"rgb(244,67,54)",
"rgb(244,67,54)",
"rgb(156,39,176)",
"rgb(103,58,183)",
"rgb(63,81,181)",
"rgb(33,150,243)",
"rgb(3,169,244)",
"rgb(0,188,212)",
"rgb(0,150,136)",
"rgb(76,175,80)",
"rgb(139,195,74)",
"rgb(205,220,57)",
"rgb(255,235,59)",
"rgb(255,193,7)",
"rgb(255,152,0)",
"rgb(255,87,34)",
"rgb(121,85,72)",
"rgb(158,158,158)",
"rgb(96,125,139)",
"rgb(0,0,0)",
];
}
}
}
ngAfterViewInit(): void {
const positionStrategy = this.overlayPositionBuilder
.flexibleConnectedTo(this.elementRef)
.withPositions(TopBottomOverlayPositions);
this.overlayRef = this.overlay.create({
positionStrategy,
hasBackdrop: true,
backdropClass: "np-color-picker-backdrop",
scrollStrategy: this.overlay.scrollStrategies.reposition(),
panelClass: this.styleClass,
});
this.templatePortal = new TemplatePortal(
this.templatePortalContent,
this.viewContainerRef
);
this.overlayRef.backdropClick().subscribe(() => this._close());
if (this.defaultOpen) {
setTimeout(() => {
this._updateStripCanvas();
this._updateBlockCanvas();
}, 10);
}
}
get value(): string {
return this.innerValue ? this.innerValue : null;
}
set value(v: string) {
if (v !== this.innerValue) {
this.innerValue = v;
this.stripColor = v;
this._setCurrentValues(v);
this.onChangeCallback(v);
this.onChange.emit(v);
}
}
writeValue(v: string): void {
if (v !== this.innerValue) {
this.innerValue = v;
this.stripColor = v;
this._setCurrentValues(v);
}
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
this.onTouchedCallback = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}
focus(): void {
this.inputViewChild.nativeElement.focus();
}
_toggleColorPicker(): void {
if (this.isOpen) {
this._close();
} else {
this._open();
}
}
_open(): void {
if (this.defaultOpen === true || this.isDisabled || this.readOnly) {
return;
}
this.isOpen = true;
this.stripColor = this.value;
if (!this.overlayRef.hasAttached()) {
this.overlayRef.attach(this.templatePortal);
}
setTimeout(() => {
this._updateStripCanvas();
this._updateBlockCanvas();
}, 10);
}
_close(): void {
if (this.defaultOpen) {
return;
}
this.isOpen = false;
this.overlayRef.detach();
this.inputViewChild.nativeElement.focus();
}
_updateStripCanvas(): void {
let strip: HTMLCanvasElement;
if (this.defaultOpen) {
strip = this.elementRef.nativeElement.querySelector(
".np-color-picker-strip"
) as HTMLCanvasElement;
} else {
strip = this.overlayRef.overlayElement.querySelector(
".np-color-picker-strip"
) as HTMLCanvasElement;
}
const ctx2 = strip.getContext("2d");
ctx2.rect(0, 0, 25, 170);
const grd1 = ctx2.createLinearGradient(0, 0, 0, 170);
grd1.addColorStop(0, "rgba(255, 0, 0, 1)");
grd1.addColorStop(0.17, "rgba(255, 255, 0, 1)");
grd1.addColorStop(0.34, "rgba(0, 255, 0, 1)");
grd1.addColorStop(0.51, "rgba(0, 255, 255, 1)");
grd1.addColorStop(0.68, "rgba(0, 0, 255, 1)");
grd1.addColorStop(0.85, "rgba(255, 0, 255, 1)");
grd1.addColorStop(1, "rgba(255, 0, 0, 1)");
ctx2.fillStyle = grd1;
ctx2.fill();
}
_updateBlockCanvas(): void {
let block: HTMLCanvasElement;
if (this.defaultOpen) {
block = this.elementRef.nativeElement.querySelector(
".np-color-picker-block"
) as HTMLCanvasElement;
} else {
block = this.overlayRef.overlayElement.querySelector(
".np-color-picker-block"
) as HTMLCanvasElement;
}
const ctx1 = block.getContext("2d");
ctx1.fillStyle = this.stripColor
? this.stripColor
: this.value
? this.value
: "rgb(255,0,0)";
ctx1.fillRect(0, 0, 170, 170);
const grdWhite = ctx1.createLinearGradient(0, 0, 170, 0);
grdWhite.addColorStop(0, "rgba(255,255,255,1)");
grdWhite.addColorStop(1, "rgba(255,255,255,0)");
ctx1.fillStyle = grdWhite;
ctx1.fillRect(0, 0, 170, 170);
const grdBlack = ctx1.createLinearGradient(0, 0, 0, 170);
grdBlack.addColorStop(0, "rgba(0,0,0,0)");
grdBlack.addColorStop(1, "rgba(0,0,0,1)");
ctx1.fillStyle = grdBlack;
ctx1.fillRect(0, 0, 170, 170);
}
_clickStripeColor(e: any): void {
const imageData = this._getColorFromClickevent(e, ".np-color-picker-strip");
this.stripColor =
this.format === "rgb"
? `rgb(${imageData[0]},${imageData[1]},${imageData[2]})`
: this._rgbToHex(imageData[0], imageData[1], imageData[2]);
this._updateBlockCanvas();
}
_clickBlockColor(e: any): void {
const imageData = this._getColorFromClickevent(e, ".np-color-picker-block");
this.value =
this.format === "rgb"
? `rgb(${imageData[0]},${imageData[1]},${imageData[2]})`
: this._rgbToHex(imageData[0], imageData[1], imageData[2]);
}
_rgbToHex(r: any, g: any, b: any): string {
const red = this._convertNumberToHex(r);
const green = this._convertNumberToHex(g);
const blue = this._convertNumberToHex(b);
return `#${red}${green}${blue}`;
}
_convertNumberToHex(num: any): string {
let hex = Number(num).toString(16);
if (hex.length < 2) {
hex = `0${hex}`;
}
return hex;
}
_hexToRgb(hex: string): any {
if (!hex) {
return null;
}
const r = parseInt(hex.substring(1, 3), 16);
const g = parseInt(hex.substring(3, 5), 16);
const b = parseInt(hex.substring(5, 7), 16);
return { r, g, b };
}
_onClickColorBlock(color: string): void {
this.value = color;
this.stripColor = this.value;
this._updateBlockCanvas();
}
_clear(): void {
if (this.isDisabled || this.readOnly) {
return;
}
this.value = null;
this._close();
}
_getColorFromClickevent(e: any, clickedElement: string): any {
let strip: HTMLCanvasElement;
if (this.defaultOpen) {
strip = this.elementRef.nativeElement.querySelector(
clickedElement
) as HTMLCanvasElement;
} else {
strip = this.overlayRef.overlayElement.querySelector(
clickedElement
) as HTMLCanvasElement;
}
const ctx2 = strip.getContext("2d");
const x = e.offsetX;
const y = e.offsetY;
return ctx2.getImageData(x, y, 1, 1).data;
}
_onKeydown(event: KeyboardEvent): void {
if (event.key === "Tab" || event.key === "Escape") {
this._close();
}
if (event.key === "ArrowDown") {
this._open();
event.preventDefault();
}
}
_onChangeHex(event: any): void {
let val = event.target.value;
if (val && val.charAt(0) !== "#") {
val = `#${event.target.value}`;
}
if (this.format === "hex") {
this.value = val;
} else {
const rgb = this._hexToRgb(val);
this.value = `rgb(${rgb.r},${rgb.g},${rgb.b})`;
}
this._updateBlockCanvas();
}
_onChangeR(event: any): void {
if (this.format === "hex") {
this.value = this._rgbToHex(
event.target.value,
this.currentG,
this.currentB
);
} else {
this.value = `rgb(${event.target.value},${this.currentG},${this.currentB})`;
}
this._updateBlockCanvas();
}
_onChangeG(event: any): void {
if (this.format === "hex") {
this.value = this._rgbToHex(
this.currentR,
event.target.value,
this.currentB
);
} else {
this.value = `rgb(${this.currentR},${event.target.value},${this.currentB})`;
}
this._updateBlockCanvas();
}
_onChangeB(event: any): void {
if (this.format === "hex") {
this.value = this._rgbToHex(
this.currentR,
this.currentG,
event.target.value
);
} else {
this.value = `rgb(${this.currentR},${this.currentG},${event.target.value})`;
}
this._updateBlockCanvas();
}
_setCurrentValues(val: string): void {
if (!val) {
this.currentHex = "";
this.currentR = null;
this.currentG = null;
this.currentB = null;
return;
}
if (this.format === "hex") {
this.currentHex = val;
const rgb = this._hexToRgb(val);
if (rgb) {
this.currentR = rgb.r;
this.currentG = rgb.g;
this.currentB = rgb.b;
}
} else {
const rgb = val
.replace("rgb", "")
.replace("(", "")
.replace(")", "")
.replace(" ", "");
const rgbAray = rgb.split(",");
this.currentR = Number(rgbAray[0]);
this.currentG = Number(rgbAray[1]);
this.currentB = Number(rgbAray[2]);
this.currentHex = this._rgbToHex(
this.currentR,
this.currentG,
this.currentB
);
}
}
_onBlur($event: any): void {
this.focused = false;
this.onTouchedCallback();
this.onBlur.emit($event);
}
_onFocus($event: any): void {
this.focused = true;
this.onFocus.emit($event);
}
_onMouseLeaveStrip(): void {
this.currentCursorColor = undefined;
}
_onMouseLeaveBlock(): void {
this.currentCursorColor = undefined;
}
_onMouseOverStrip(e: any): void {
this.xColorCursor = `${e.pageX}px`;
this.yColorCursor = `${e.pageY}px`;
const imageData = this._getColorFromClickevent(e, ".np-color-picker-strip");
this.currentCursorColor =
this.format === "rgb"
? `rgb(${imageData[0]},${imageData[1]},${imageData[2]})`
: this._rgbToHex(imageData[0], imageData[1], imageData[2]);
}
_onMouseOverBlock(e: any): void {
this.xColorCursor = `${e.pageX}px`;
this.yColorCursor = `${e.pageY}px`;
const imageData = this._getColorFromClickevent(e, ".np-color-picker-block");
this.currentCursorColor =
this.format === "rgb"
? `rgb(${imageData[0]},${imageData[1]},${imageData[2]})`
: this._rgbToHex(imageData[0], imageData[1], imageData[2]);
}
}
Example #18
Source File: calendar.ts From angular-material-components with MIT License | 4 votes |
/**
* A calendar that is used as part of the datepicker.
* @docs-private
*/
@Component({
selector: 'ngx-mat-calendar',
templateUrl: 'calendar.html',
styleUrls: ['calendar.scss'],
host: {
'class': 'mat-calendar',
},
exportAs: 'ngxMatCalendar',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NgxMatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDestroy, OnChanges {
/** An input indicating the type of the header component, if set. */
@Input() headerComponent: ComponentType<any>;
/** A portal containing the header component type for this calendar. */
_calendarHeaderPortal: Portal<any>;
private _intlChanges: Subscription;
/**
* Used for scheduling that focus should be moved to the active cell on the next tick.
* We need to schedule it, rather than do it immediately, because we have to wait
* for Angular to re-evaluate the view children.
*/
private _moveFocusOnNextTick = false;
/** A date representing the period (month or year) to start the calendar in. */
@Input()
get startAt(): D | null { return this._startAt; }
set startAt(value: D | null) {
this._startAt = this._getValidDateOrNull(this._dateAdapter.deserialize(value));
}
private _startAt: D | null;
/** Whether the calendar should be started in month or year view. */
@Input() startView: MatCalendarView = 'month';
/** The currently selected date. */
@Input()
get selected(): D | null { return this._selected; }
set selected(value: D | null) {
this._selected = this._getValidDateOrNull(this._dateAdapter.deserialize(value));
}
private _selected: D | null;
/** The minimum selectable date. */
@Input()
get minDate(): D | null { return this._minDate; }
set minDate(value: D | null) {
this._minDate = this._getValidDateOrNull(this._dateAdapter.deserialize(value));
}
private _minDate: D | null;
/** The maximum selectable date. */
@Input()
get maxDate(): D | null { return this._maxDate; }
set maxDate(value: D | null) {
this._maxDate = this._getValidDateOrNull(this._dateAdapter.deserialize(value));
}
private _maxDate: D | null;
/** Function used to filter which dates are selectable. */
@Input() dateFilter: (date: D) => boolean;
/** Function that can be used to add custom CSS classes to dates. */
@Input() dateClass: (date: D) => MatCalendarCellCssClasses;
/** Emits when the currently selected date changes. */
@Output() readonly selectedChange: EventEmitter<D> = new EventEmitter<D>();
/**
* Emits the year chosen in multiyear view.
* This doesn't imply a change on the selected date.
*/
@Output() readonly yearSelected: EventEmitter<D> = new EventEmitter<D>();
/**
* Emits the month chosen in year view.
* This doesn't imply a change on the selected date.
*/
@Output() readonly monthSelected: EventEmitter<D> = new EventEmitter<D>();
/** Emits when any date is selected. */
@Output() readonly _userSelection: EventEmitter<void> = new EventEmitter<void>();
/** Reference to the current month view component. */
@ViewChild(NgxMatMonthView) monthView: NgxMatMonthView<D>;
/** Reference to the current year view component. */
@ViewChild(NgxMatYearView) yearView: NgxMatYearView<D>;
/** Reference to the current multi-year view component. */
@ViewChild(NgxMatMultiYearView) multiYearView: NgxMatMultiYearView<D>;
/**
* The current active date. This determines which time period is shown and which date is
* highlighted when using keyboard navigation.
*/
get activeDate(): D { return this._clampedActiveDate; }
set activeDate(value: D) {
this._clampedActiveDate = this._dateAdapter.clampDate(value, this.minDate, this.maxDate);
this.stateChanges.next();
this._changeDetectorRef.markForCheck();
}
private _clampedActiveDate: D;
/** Whether the calendar is in month view. */
get currentView(): MatCalendarView { return this._currentView; }
set currentView(value: MatCalendarView) {
this._currentView = value;
this._moveFocusOnNextTick = true;
this._changeDetectorRef.markForCheck();
}
private _currentView: MatCalendarView;
/**
* Emits whenever there is a state change that the header may need to respond to.
*/
stateChanges = new Subject<void>();
constructor(_intl: MatDatepickerIntl,
@Optional() private _dateAdapter: NgxMatDateAdapter<D>,
@Optional() @Inject(NGX_MAT_DATE_FORMATS) private _dateFormats: NgxMatDateFormats,
private _changeDetectorRef: ChangeDetectorRef) {
if (!this._dateAdapter) {
throw createMissingDateImplError('NgxDateAdapter');
}
if (!this._dateFormats) {
throw createMissingDateImplError('NGX_MAT_DATE_FORMATS');
}
this._intlChanges = _intl.changes.subscribe(() => {
_changeDetectorRef.markForCheck();
this.stateChanges.next();
});
}
ngAfterContentInit() {
this._calendarHeaderPortal = new ComponentPortal(this.headerComponent || NgxMatCalendarHeader);
this.activeDate = this.startAt || this._dateAdapter.today();
// Assign to the private property since we don't want to move focus on init.
this._currentView = this.startView;
}
ngAfterViewChecked() {
if (this._moveFocusOnNextTick) {
this._moveFocusOnNextTick = false;
this.focusActiveCell();
}
}
ngOnDestroy() {
this._intlChanges.unsubscribe();
this.stateChanges.complete();
}
ngOnChanges(changes: SimpleChanges) {
const change =
changes['minDate'] || changes['maxDate'] || changes['dateFilter'];
if (change && !change.firstChange) {
const view = this._getCurrentViewComponent();
if (view) {
// We need to `detectChanges` manually here, because the `minDate`, `maxDate` etc. are
// passed down to the view via data bindings which won't be up-to-date when we call `_init`.
this._changeDetectorRef.detectChanges();
view._init();
}
}
this.stateChanges.next();
}
focusActiveCell() {
this._getCurrentViewComponent()._focusActiveCell();
}
/** Updates today's date after an update of the active date */
updateTodaysDate() {
let view = this.currentView == 'month' ? this.monthView :
(this.currentView == 'year' ? this.yearView : this.multiYearView);
view.ngAfterContentInit();
}
/** Handles date selection in the month view. */
_dateSelected(date: D | null): void {
if (date && !this._dateAdapter.sameDate(date, this.selected)) {
this.selectedChange.emit(date);
}
}
/** Handles year selection in the multiyear view. */
_yearSelectedInMultiYearView(normalizedYear: D) {
this.yearSelected.emit(normalizedYear);
}
/** Handles month selection in the year view. */
_monthSelectedInYearView(normalizedMonth: D) {
this.monthSelected.emit(normalizedMonth);
}
_userSelected(): void {
this._userSelection.emit();
}
/** Handles year/month selection in the multi-year/year views. */
_goToDateInView(date: D, view: 'month' | 'year' | 'multi-year'): void {
this.activeDate = date;
this.currentView = view;
}
/**
* @param obj The object to check.
* @returns The given object if it is both a date instance and valid, otherwise null.
*/
private _getValidDateOrNull(obj: any): D | null {
return (this._dateAdapter.isDateInstance(obj) && this._dateAdapter.isValid(obj)) ? obj : null;
}
/** Returns the component instance that corresponds to the current calendar view. */
private _getCurrentViewComponent() {
return this.monthView || this.yearView || this.multiYearView;
}
}
Example #19
Source File: np-date-picker.component.ts From np-ui-lib with MIT License | 4 votes |
@Component({
selector: "np-date-picker",
templateUrl: "./np-date-picker.component.html",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.Default,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NpDatePickerComponent),
multi: true,
},
],
})
export class NpDatePickerComponent
implements ControlValueAccessor, AfterViewInit, AfterContentInit {
private static controlCount = 1;
@Input() minDate: Date;
@Input() maxDate: Date;
@Input() format: string = "dd/MM/yyyy";
@Input() defaultOpen: boolean = false;
@Input() showTodayButton: boolean = false;
@Input() disableWeekDays: string[] = [];
@Input() disableDates: Date[] = [];
@Input() dateLabels: any[] = [];
@Input() dateClass: any;
@Input() isStartMonthWithMonday = false;
@Input() placeholder: string = "";
@Input() readOnly: boolean;
@Input() autoFocus: boolean;
@Input() tabIndex: number;
@Input() styleClass: string;
@Input() inputId: string = `np-date-picker_${NpDatePickerComponent.controlCount++}`;
@Output() onChange: EventEmitter<any> = new EventEmitter();
@Output() onFocus: EventEmitter<any> = new EventEmitter();
@Output() onBlur: EventEmitter<any> = new EventEmitter();
@ViewChild("templatePortalContent") templatePortalContent: TemplateRef<any>;
@ViewChild("control") inputViewChild: ElementRef;
weekDays: string[];
monthsList: any[];
months: any[];
years: number[] = [];
currentMonthWeeks: any;
currentMonth: number;
currentYear: number;
today: Date;
isOpen: boolean = false;
innerValue: Date;
isDisabled: boolean = false;
originalWeekDays: string[] = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
focused: boolean = false;
private templatePortal: TemplatePortal<any>;
private overlayRef: OverlayRef;
private onChangeCallback: (_: any) => void = () => { };
private onTouchedCallback: () => void = () => { };
constructor(
public overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private overlayPositionBuilder: OverlayPositionBuilder,
private elementRef: ElementRef,
private utility: NpUtilityService
) {
this.monthsList = [
{ key: 0, value: "January" },
{ key: 1, value: "February" },
{ key: 2, value: "March" },
{ key: 3, value: "April" },
{ key: 4, value: "May" },
{ key: 5, value: "June" },
{ key: 6, value: "July" },
{ key: 7, value: "August" },
{ key: 8, value: "September" },
{ key: 9, value: "October" },
{ key: 10, value: "November" },
{ key: 11, value: "December" },
];
this.today = new Date();
this.today.setHours(0, 0, 0, 0);
}
ngAfterContentInit(): void {
if (this.isStartMonthWithMonday) {
this.weekDays = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
} else {
this.weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
}
if (this.defaultOpen) {
this._resetVariables();
}
}
ngAfterViewInit(): void {
const positionStrategy = this.overlayPositionBuilder
.flexibleConnectedTo(this.elementRef)
.withPositions(TopBottomOverlayPositions);
this.overlayRef = this.overlay.create({
positionStrategy,
hasBackdrop: true,
backdropClass: "np-date-picker-backdrop",
scrollStrategy: this.overlay.scrollStrategies.reposition(),
panelClass: this.styleClass,
});
this.templatePortal = new TemplatePortal(
this.templatePortalContent,
this.viewContainerRef
);
this.overlayRef.backdropClick().subscribe(() => this._close());
}
get value(): Date {
return this.innerValue ? this.innerValue : null;
}
set value(v: Date) {
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
this.onChange.emit(v);
}
}
writeValue(v: Date): void {
if (v !== this.innerValue) {
this.innerValue = v;
if (this._checkIsFullDateDisabled(v)) {
this.value = null;
}
}
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
this.onTouchedCallback = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}
focus(): void {
this.inputViewChild.nativeElement.focus();
}
_resetVariables(): void {
if (this.value) {
if (this.minDate && this.minDate > this.value) {
this.value = null;
}
if (this.maxDate && this.maxDate < this.value) {
this.value = null;
}
}
let currentDate =
this.value && this.value.toString() !== "Invalid Date"
? this.value
: this.today;
if (this.minDate && currentDate < this.minDate) {
currentDate = this.minDate;
}
if (this.maxDate && currentDate > this.maxDate) {
currentDate = this.maxDate;
}
this.currentMonth = currentDate.getMonth();
this.currentYear = currentDate.getFullYear();
this._calculateDays();
}
_calculateDays(): void {
const weeks = [];
weeks[0] = [];
const daysInMonth = this._getCurrentMonthData();
const firstWeekDayOfMonth = new Date(
this.currentYear,
this.currentMonth,
1
).getDay();
// push extra values up to week days match to start date if month
for (let index = 0; index < firstWeekDayOfMonth; index++) {
weeks[0].push({ disabled: true });
}
if (this.isStartMonthWithMonday) {
// if start with monday then
if (firstWeekDayOfMonth === 0) {
weeks[0].push(
{ disabled: true },
{ disabled: true },
{ disabled: true },
{ disabled: true },
{ disabled: true },
{ disabled: true }
);
} else {
weeks[0].pop();
}
}
let j = 0;
// push all dates in month
daysInMonth.forEach((element: any) => {
if (weeks[j].length === 7) {
j++;
weeks[j] = [];
}
weeks[j].push(element);
});
this.currentMonthWeeks = weeks;
}
_getCurrentMonthData(): any[] {
const data = [];
const totalDaysInMonth = this._daysInCurrentMonth();
for (let i = 1; i <= totalDaysInMonth; i++) {
const date = new Date(this.currentYear, this.currentMonth, i);
data.push({
date,
day: i,
disabled: this._checkIsFullDateDisabled(date),
today: this._compareDate(this.today, date),
selected: this._compareDate(this.value, date),
toolTip: this._getTooltip(date),
});
}
return data;
}
_daysInCurrentMonth(): number {
let days = 0;
switch (this.currentMonth) {
case 0: // Jan
case 2: // Mar
case 4: // May
case 6: // Jul
case 7: // Aug
case 9: // Oct
case 11: // Dec
days = 31;
break;
case 3: // Apr
case 5: // Jun
case 8: // Sept
case 10: // Nov
days = 30;
break;
case 1: // Feb
days = this.currentYear % 4 === 0 ? 29 : 28;
break;
}
return days;
}
_prevMonth(): void {
if (this.currentMonth === 0) {
this.currentMonth = 11;
this.currentYear = this.currentYear - 1;
} else {
this.currentMonth = this.currentMonth - 1;
}
this._calculateDays();
}
_nextMonth(): void {
if (this.currentMonth === 11) {
this.currentMonth = 0;
this.currentYear = this.currentYear + 1;
} else {
this.currentMonth = this.currentMonth + 1;
}
this._calculateDays();
}
_selectDate(date: Date): void {
if (
date === null ||
this._checkIsFullDateDisabled(date) ||
this.isDisabled ||
this.readOnly
) {
return;
}
this._setSelectedDate(date);
this._close();
}
_selectMonth($event: any): void {
this.currentMonth = Number($event.target.value);
this._calculateDays();
}
_changeYear($event: any): void {
this.currentYear = Number($event.target.value.trim());
this._calculateDays();
}
_toggleDatePicker(): void {
if (this.isOpen) {
this._close();
} else {
this._open();
}
}
_open(): void {
if (this.defaultOpen === true || this.isDisabled || this.readOnly) {
return;
}
this.isOpen = true;
this._resetVariables();
if (!this.overlayRef.hasAttached()) {
this.overlayRef.attach(this.templatePortal);
}
}
_close(): void {
if (this.defaultOpen) {
return;
}
this.isOpen = false;
this.overlayRef.detach();
this.inputViewChild.nativeElement.focus();
}
_setToday(): void {
if (this._checkIsFullDateDisabled(this.today)) {
return;
}
this._setSelectedDate(this.today);
this._calculateDays();
this._close();
}
_clear(): void {
if (this.isDisabled || this.readOnly) {
return;
}
this._setSelectedDate(null);
this._calculateDays();
this._close();
}
_getTooltip(currentDate: Date): void {
if (currentDate && this.dateLabels && this.dateLabels.length > 0) {
const dateLabel: any = this.dateLabels.find((item) => this._compareDate(item.date, currentDate));
return dateLabel ? dateLabel.label : null;
}
return null;
}
_checkIsWeekDayDisabled(index: number): boolean {
const day = this.originalWeekDays[index];
return this.disableWeekDays.indexOf(day) > -1;
}
_checkIsFullDateDisabled(date: Date): boolean {
if (date === undefined || date === null) {
return false;
}
if (this.minDate && date < this.minDate) {
return true;
}
if (this.maxDate && date > this.maxDate) {
return true;
}
if (this._checkIsWeekDayDisabled(date.getDay())) {
return true;
}
return (this.disableDates.findIndex((item) => this._compareDate(item, date))) > -1;
}
_setSelectedDate(date: Date): void {
if (date) {
date.setHours(0, 0, 0, 0);
}
if (this._checkIsFullDateDisabled(date)) {
return;
}
this.value = date;
this._resetVariables();
}
_onKeydown(event: KeyboardEvent): void {
if (event.key === "Tab" || event.key === "Escape") {
this._close();
}
if (event.key === "ArrowDown") {
this._open();
event.preventDefault();
}
}
_onInputChange($event: any): void {
const date = this.utility.ReverseFormatDate(
$event.target.value.trim(),
this.format
);
if (date === "Invalid Date") {
$event.target.value = "";
this.value = null;
return;
}
if (this._checkIsFullDateDisabled(date)) {
this.value = null;
return;
}
this.value = date;
this._resetVariables();
}
_compareDate(dateA: Date, dateB: Date): boolean {
if (!dateA || !dateB) {
return false;
}
if (
dateA.getFullYear() === dateB.getFullYear() &&
dateA.getMonth() === dateB.getMonth() &&
dateA.getDate() === dateB.getDate()
) {
return true;
}
return false;
}
_onBlur($event: any): void {
this.focused = false;
this.onTouchedCallback();
this.onBlur.emit($event);
}
_onFocus($event: any): void {
this.focused = true;
this.onFocus.emit($event);
}
_getDateClass(item: any): string {
if (this.dateClass) {
return (
`np-date-picker-day np-day-${item.day} ` + this.dateClass(item.date)
).trim();
}
return `np-date-picker-day np-day-${item.day}`;
}
}
Example #20
Source File: app-sidenav.component.ts From youpez-admin with MIT License | 4 votes |
@Component({
selector: 'youpez-sidenav',
templateUrl: './app-sidenav.component.html',
styleUrls: ['./app-sidenav.component.scss'],
})
export class AppSidenavComponent implements OnInit, OnDestroy, AfterContentInit, OnChanges, AfterViewInit, AfterViewChecked {
@Input('opened') originalOpened: boolean
@Input() direction: DirectionType = 'left'
@Input() size: SizeType = 'md'
@Input('mode') originalMode: ModeType = 'over'
@Input() breakpoint: string = ''
@Input() transparent: boolean = false
@Input() toggleableBtn: boolean = false
@Input() toggleableBtnAlwaysVisible: boolean = false
@Input('hoverAble') originalHoverAble: boolean = false
@Input() hoverAbleBreakpoint: string = 'md'
@Input() optionalClass: string = ''
@Input() initWidth: string = ''
@Input() hoverDelay: number = 100
@Input() minDimension: number = null
@Output() open: EventEmitter<any> = new EventEmitter<any>()
@Output() close: EventEmitter<any> = new EventEmitter<any>()
@Output() init: EventEmitter<any> = new EventEmitter<any>()
@Output() change: EventEmitter<any> = new EventEmitter<any>()
@Output() resizeEnd: EventEmitter<any> = new EventEmitter<any>()
@Output() resizing: EventEmitter<any> = new EventEmitter<any>()
@Output() visibleChange: EventEmitter<any> = new EventEmitter<any>()
@ViewChild('sideNavEl', {static: true}) sideNavEl: ElementRef
public rendered: boolean = false
public width: string = ''
public height: string = ''
public mode: string = 'over'
public hoverEvent: boolean = false
public hoverAble: boolean = false
public opened: boolean = false
public openedMemo:boolean = null
public isMouseEntered: boolean = false
public resizeEdges = {
bottom: false,
right: false,
top: false,
left: false,
}
private lock: boolean = false
private hoverTimeout = null
private breakpointSub: Subscription
private dimensions = {
width: {
docs: '170',
xsm: '200',
sm: '300',
md: '300',
lg: '500',
xl: '800',
custom1: '260',
sideBar1: '240',
sideBar2: '300',
mail: '380',
mini: '100',
},
height: {},
}
constructor(public element: ElementRef,
private appBreakpointService: AppBreakpointService,
private appSidenavService: AppSidenavService,) {
}
ngOnInit() {
this.firstInit()
//CURRENTLY: https://github.com/angular/flex-layout/issues/1059
this.breakpointSub = this.appBreakpointService.$windowWidth
.subscribe((width: any) => {
if (!width) {
return
}
if (this.breakpoint && this.breakpoint === 'md') {
if (width <= 960) {
this.mode = 'over'
this.hoverAble = false
this.opened = false
this.openedMemo = this.originalOpened
setTimeout(() => {
this.visibleChange.emit(false)
}, 1)
}
else {
this.mode = this.originalMode
this.hoverAble = this.originalHoverAble
this.opened = this.openedMemo || this.originalOpened
setTimeout(() => {
this.visibleChange.emit(this.openedMemo || this.originalOpened)
}, 1)
}
this.change.emit()
}
})
}
private firstInit() {
let {initWidth, size, originalMode, originalHoverAble, originalOpened, direction} = this
if (initWidth) {
this.setWidth(initWidth)
this.setHeight(initWidth)
}
else {
this.setWidth(this.dimensions.width[size])
this.setHeight(this.dimensions.width[size])
}
this.mode = originalMode
this.hoverAble = originalHoverAble
this.opened = originalOpened
if (originalMode === 'side') {
if (direction === 'right') {
this.resizeEdges.left = true
}
if (direction === 'left') {
this.resizeEdges.right = true
}
if (direction === 'top') {
this.resizeEdges.bottom = true
}
if (direction === 'bottom') {
this.resizeEdges.top = true
}
}
}
ngOnChanges(changes: SimpleChanges): void {
const opened: SimpleChange = changes.originalOpened
if (opened !== undefined && opened.previousValue !== undefined) {
const currentOpened = opened.currentValue
if (currentOpened) {
this.onOpen()
}
else {
this.onClose()
}
}
}
ngOnDestroy(): void {
if (this.breakpointSub) {
this.breakpointSub.unsubscribe()
}
}
ngAfterContentInit() {
if (this.originalMode !== 'side') {
setTimeout(() => {
this.rendered = true
}, 450)
}
else {
this.rendered = true
}
}
ngAfterViewInit() {
}
ngAfterViewChecked() {
}
setWidth(width) {
this.width = width
if (Number(this.width) <= 200) {
this.onClose()
setTimeout(() => {
this.width = '200'
}, 1000)
}
}
setHeight(height) {
this.height = height
}
sendChange(changes = null) {
this.change.emit()
}
setPanelStyle(panel: PanelType) {
let panelCss = ''
if (panel === 'panel') {
panelCss = 'app-sidenav-v2--panel'
}
if (panel === 'solid') {
panelCss = 'app-sidenav-v2--solid-border'
}
this.optionalClass = this.optionalClass + ' ' + panelCss
}
getWidth() {
return this.width
}
getMainCSSclass() {
return `app-sidenav-v2 ${this.optionalClass}`
}
getHeight() {
return this.height
}
getMinDimension() {
return this.minDimension
}
onClose() {
this.opened = false
this.visibleChange.emit(false)
this.close.emit()
}
onOpen() {
this.opened = true
this.visibleChange.emit(true)
this.open.emit()
}
onToggle() {
if (this.opened) {
this.onClose()
this.onMouseLeave('')
}
else {
this.onOpen()
}
}
isOpened() {
return this.opened
}
emitInitForParent() {
this.init.emit()
}
onForceHover(bool = true) {
if (this.hoverAble) {
if (!this.isMouseEntered) {
this.hoverEvent = bool
}
}
else {
this.onOpen()
}
}
onMouseEnter(event) {
this.isMouseEntered = true
if (this.hoverTimeout) {
clearTimeout(this.hoverTimeout)
}
this.hoverTimeout = setTimeout(() => {
const element = event.target
if (element.classList.contains('app-sidenav-v2__inner')) {
this.hoverEvent = true
}
}, this.hoverDelay)
}
onMouseLeave(event) {
if (this.lock) {
return
}
this.isMouseEntered = false
if (this.hoverTimeout) {
clearTimeout(this.hoverTimeout)
}
this.hoverEvent = false
}
onResizeEnd(event: ResizeEvent) {
const {edges, rectangle} = event
const {right, left, bottom, top} = edges
const {width, height} = rectangle
const calcWidth = Number(width)
const calcHeight = Number(height)
this.setWidth(calcWidth)
this.setHeight(calcHeight)
this.sendChange()
if (this.direction === 'top' || this.direction === 'bottom') {
this.resizeEnd.next(calcHeight)
}
else {
this.resizeEnd.next(calcWidth)
}
this.lock = false
}
onResize(event: ResizeEvent) {
const {edges, rectangle} = event
const {right, left, bottom, top} = edges
const {width, height} = rectangle
const calcWidth = Number(width)
const calcHeight = Number(height)
this.setWidth(calcWidth)
this.setHeight(calcHeight)
this.sendChange({windowResize: false})
if (this.direction === 'top' || this.direction === 'bottom') {
this.resizing.next(calcHeight)
}
else {
this.resizing.next(calcWidth)
}
}
onResizeStart(event: ResizeEvent) {
this.onForceHover(true)
this.lock = true
}
onSetDefaultWidth(event) {
this.setWidth(this.dimensions.width[this.size])
}
}
Example #21
Source File: facet-card.ts From sba-angular with MIT License | 4 votes |
@Component({
selector: "sq-facet-card",
templateUrl: "./facet-card.html",
styles: [`
.cursor-default {cursor: default;}
`]
})
export class BsFacetCard implements OnInit, OnDestroy, AfterContentInit {
/**
* Title of this facet (optional)
*/
@Input() title: string;
/**
* Tooltip of this facet (defaults to title)
*/
@Input() tooltip: string;
/**
* Icon of this facet, in a form of a span class name (optional)
*/
@Input() icon: string;
/**
* Bootstrap theme name (light, dark...)
*/
@Input() buttonsStyle: string;
/**
* List of custom actions for this facet (optional)
*/
@Input() actions: Action[] = [];
/**
* Whether the [actions]="..." passed by binding should be displayed before or after
* the actions from the inner facet component
*/
@Input() actionsFirst = true;
/**
* Size of the custom actions
*/
@Input() actionsSize = "sm";
/**
* Whether the facet can be collapsed (default: true)
*/
@Input() collapsible: boolean = true;
/**
* Whether the facet starts collapsed (if collapsible / default: false)
*/
@Input() startCollapsed: boolean = false;
/**
* Whether other actions should be hidden when the facet is collapsed (default: true)
*/
@Input() hideActionsCollapsed: boolean = true;
/**
* Whether the facet can be expanded (default: false)
*/
@Input() expandable: boolean = false;
/**
* Whether the facet starts expanded (if expandable / default: false)
*/
@Input() startExpanded: boolean = false;
/**
* Facet will collapse automatically once clicking outside of it
*/
@Input() collapseOnClickOutside: boolean = false;
/**
* Whether the facet starts with opened settings (default: false)
*/
@Input() startSettingsOpened: boolean = false;
/**
* Event triggered when the facet gets expanded or reduced
*/
@Output() facetExpanded = new EventEmitter<"expanded"|"reduced">();
/**
* Event triggered when the facet gets expanded or reduced
*/
@Output() facetCollapsed = new EventEmitter<"collapsed"|"expanded">();
/**
* Event triggered when the facet gets expanded or reduced
*/
@Output() settingsOpened = new EventEmitter<"opened"|"saved"|"canceled">();
/**
* Reference to the child facet inserted by transclusion (ng-content)
*/
@ContentChild("facet", {static: false}) public facetComponent: AbstractFacet;
@HostBinding('class.collapsed') _collapsed: boolean;
@HostBinding('class.expanded') _expanded: boolean;
@HostBinding('class.settings-opened') _settingsOpened: boolean;
@HostBinding('hidden') get hidden(): boolean {
return !!this.facetComponent && !!this.facetComponent.isHidden && this.facetComponent.isHidden();
}
public readonly collapseAction;
public readonly expandAction;
public readonly settingsAction;
private actionChangedSubscription: Subscription;
constructor(
private changeDetectorRef: ChangeDetectorRef
){
this.collapseAction = new Action({
action: (action) => {
this._collapsed = !this._collapsed;
this.facetCollapsed.next(this._collapsed ? "collapsed" : "expanded");
if(!!this.facetComponent){
this.facetComponent.onCollapse(this._collapsed);
}
action.update();
},
updater: (action) => {
action.icon = this._collapsed ? "fas fa-chevron-down" : "fas fa-chevron-up";
action.title = this._collapsed ? 'msg#facetCard.expand' : 'msg#facetCard.collapse';
}
});
this.expandAction = new Action({
action: (action) => {
this._expanded = !this._expanded;
this.facetExpanded.next(this._expanded ? "expanded" : "reduced");
if(!!this.facetComponent){
this.facetComponent.onExpand(this._expanded);
}
action.update();
},
updater: (action) => {
action.icon = this._expanded ? "fas fa-compress" : "fas fa-expand";
action.title = this._expanded ? "msg#facetCard.reduce" : "msg#facetCard.enlarge";
}
});
this.settingsAction = new Action({
action: (action) => {
this._settingsOpened = !this._settingsOpened;
this.settingsOpened.next(this._settingsOpened? "opened" : "saved");
if(!!this.facetComponent){
this.facetComponent.onOpenSettings(this._settingsOpened);
}
action.update();
},
updater: (action) => {
action.icon = this._settingsOpened ? "far fa-save" : "fas fa-cog";
action.title = this._settingsOpened ? "msg#facetCard.saveSettings" : "msg#facetCard.openSettings";
}
});
}
ngOnInit(){
// Initialize actions
this._collapsed = this.startCollapsed;
this._expanded = this.startExpanded;
this._settingsOpened = this.startSettingsOpened;
this.collapseAction.update();
this.expandAction.update();
this.settingsAction.update();
}
ngAfterContentInit(){
if(this.facetComponent) {
this.actionChangedSubscription = this.facetComponent.actionsChanged.subscribe((actions) => {
this.allActions.forEach(action => action.update());
this.changeDetectorRef.markForCheck();
});
}
else {
console.warn("No #facet component is defined in this facet card: ", this.title);
}
}
ngOnDestroy(){
if(this.actionChangedSubscription){
this.actionChangedSubscription.unsubscribe();
}
}
public get allActions() : Action[] {
if(this.hideActionsCollapsed && this._collapsed) return [this.collapseAction]; // Hide other actions if collapsed
let actions = [] as Action[];
if(this.actionsFirst) {
actions.push(...this.actions);
}
if(this.facetComponent) actions = actions.concat(this.facetComponent.actions);
if(this.hasSettings) actions.push(this.settingsAction);
if(this.expandable) actions.push(this.expandAction);
if(this.collapsible) actions.push(this.collapseAction);
if(!this.actionsFirst) {
actions.push(...this.actions);
}
return actions;
}
public get hasSettings(){
return !!this.facetComponent && !!this.facetComponent.settingsTpl;
}
@HostListener('window:click', ['$event'])
clickOut() {
if (this.collapseOnClickOutside) {
this._collapsed = true;
this.collapseAction.update();
this.expandAction.update();
this.settingsAction.update();
}
}
}
Example #22
Source File: vg-player.ts From ngx-videogular with MIT License | 4 votes |
@Component({
selector: 'vg-player',
encapsulation: ViewEncapsulation.None,
template: `<ng-content></ng-content>`,
styles: [`
vg-player {
font-family: 'videogular';
position: relative;
display: flex;
width: 100%;
height: 100%;
overflow: hidden;
background-color: black;
}
vg-player.fullscreen {
position: fixed;
left: 0;
top: 0;
}
vg-player.native-fullscreen.controls-hidden {
cursor: none;
}
` ],
providers: [VgAPI, VgFullscreenAPI, VgControlsHidden]
})
// tslint:disable:component-class-suffix
// tslint:disable:no-output-on-prefix
export class VgPlayer implements AfterContentInit, OnDestroy {
elem: HTMLElement;
@HostBinding('class.fullscreen') isFullscreen = false;
@HostBinding('class.native-fullscreen') isNativeFullscreen = false;
@HostBinding('class.controls-hidden') areControlsHidden = false;
@HostBinding('style.z-index') zIndex: string;
@Output()
onPlayerReady: EventEmitter<any> = new EventEmitter();
@Output()
onMediaReady: EventEmitter<any> = new EventEmitter();
@ContentChildren(VgMedia)
medias: QueryList<VgMedia>;
subscriptions: Subscription[] = [];
constructor(ref: ElementRef, public api: VgAPI, public fsAPI: VgFullscreenAPI, private controlsHidden: VgControlsHidden) {
this.elem = ref.nativeElement;
this.api.registerElement(this.elem);
}
ngAfterContentInit() {
this.medias.toArray().forEach((media) => {
this.api.registerMedia(media);
});
this.fsAPI.init(this.elem, this.medias);
this.subscriptions.push(this.fsAPI.onChangeFullscreen.subscribe(this.onChangeFullscreen.bind(this)));
this.subscriptions.push(this.controlsHidden.isHidden.subscribe(this.onHideControls.bind(this)));
this.api.onPlayerReady(this.fsAPI);
this.onPlayerReady.emit(this.api);
}
onChangeFullscreen(fsState: boolean) {
if (!this.fsAPI.nativeFullscreen) {
this.isFullscreen = fsState;
this.zIndex = fsState ? VgUtils.getZIndex().toString() : 'auto';
} else {
this.isNativeFullscreen = fsState;
}
}
onHideControls(hidden: boolean) {
this.areControlsHidden = hidden;
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
}
Example #23
Source File: index.ts From nativescript-plugins with Apache License 2.0 | 4 votes |
@Directive()
export abstract class AccordionItemsComponent implements DoCheck, OnDestroy, AfterContentInit {
public abstract get nativeElement(): any;
protected accordionItemsView: any;
protected _items: any;
protected _differ: IterableDiffer<KeyedTemplate>;
protected _templateHeaderMap: Map<string, KeyedTemplate>;
protected _templateItemHeaderMap: Map<string, KeyedTemplate>;
protected _templateItemContentMap: Map<string, KeyedTemplate>;
protected _templateFooterMap: Map<string, KeyedTemplate>;
@ViewChild('loader', {read: ViewContainerRef, static: false})
loader: ViewContainerRef;
@Output()
public setupItemView = new EventEmitter<SetupItemViewArgs>();
@ContentChild(TemplateRef, {static: false})
itemTemplateQuery: TemplateRef<ItemContext>;
headerTemplate: TemplateRef<ItemContext>;
itemHeaderTemplate: TemplateRef<ItemContext>;
itemContentTemplate: TemplateRef<ItemContext>;
footerTemplate: TemplateRef<ItemContext>;
@Input()
get items() {
return this._items;
}
set items(value: any) {
this._items = value;
let needDiffer = true;
if (value instanceof ObservableArray) {
needDiffer = false;
}
if (needDiffer && !this._differ && isListLikeIterable(value)) {
this._differ = this._iterableDiffers.find(this._items)
.create((_index, item) => {
return item;
});
}
this.accordionItemsView.items = this._items;
}
constructor(_elementRef: ElementRef,
private _iterableDiffers: IterableDiffers) {
this.accordionItemsView = _elementRef.nativeElement;
this.accordionItemsView.on('headerLoading', this.onHeaderLoading, this);
this.accordionItemsView.on('itemHeaderLoading', this.onItemHeaderLoading, this);
this.accordionItemsView.on('itemContentLoading', this.onItemContentLoading, this);
this.accordionItemsView.on('footerLoading', this.onFooterLoading, this);
}
ngAfterContentInit() {
this.setItemTemplates();
}
ngOnDestroy() {
this.accordionItemsView.off('headerLoading', this.onHeaderLoading, this);
this.accordionItemsView.off('itemHeaderLoading', this.onItemHeaderLoading, this);
this.accordionItemsView.off('itemContentLoading', this.onItemContentLoading, this);
this.accordionItemsView.off('footerLoading', this.onFooterLoading, this);
}
private setItemTemplates() {
this.itemHeaderTemplate = this.itemTemplateQuery;
this.accordionItemsView._getHasHeader = () => {
return false;
};
this.accordionItemsView._getHasFooter = () => {
return false;
};
if (this._templateHeaderMap) {
const templates: KeyedTemplate[] = [];
this._templateHeaderMap.forEach(value => {
templates.push(value);
});
if (templates.length === 1) {
this.accordionItemsView.headerTemplateSelector = (item: any, index: number, items: any) => {
return 'header';
};
}
if (templates.length > 0) {
this.accordionItemsView._getHasHeader = () => {
return true;
};
}
this.accordionItemsView.headerTemplates = templates;
}
if (this._templateItemHeaderMap) {
const templates: KeyedTemplate[] = [];
this._templateItemHeaderMap.forEach(value => {
templates.push(value);
});
this.accordionItemsView.itemHeaderTemplates = templates;
if (templates.length === 1) {
this.accordionItemsView.itemHeaderTemplateSelector = (item: any, index: number, items: any) => {
return 'title';
};
}
} else {
this.getItemTemplateViewFactory(this.itemHeaderTemplate);
}
if (this._templateItemContentMap) {
const templates: KeyedTemplate[] = [];
this._templateItemContentMap.forEach(value => {
templates.push(value);
});
if (templates.length === 1) {
this.accordionItemsView.itemContentTemplateSelector = (item: any, parentIndex: number, index: number, items: any) => {
return 'content';
};
}
this.accordionItemsView.itemContentTemplates = templates;
}
if (this._templateFooterMap) {
const templates: KeyedTemplate[] = [];
this._templateFooterMap.forEach(value => {
templates.push(value);
});
if (templates.length === 1) {
this.accordionItemsView.footerTemplateSelector = (item: any, index: number, items: any) => {
return 'footer';
};
}
if (templates.length > 0) {
this.accordionItemsView._getHasFooter = () => {
return true;
};
}
this.accordionItemsView.footerTemplates = templates;
}
}
public registerTemplate(key: string, template: TemplateRef<ItemContext>) {
if (key === 'header' || key.startsWith('header-')) {
if (!this._templateHeaderMap) {
this._templateHeaderMap = new Map<string, KeyedTemplate>();
}
const keyedTemplate = {
key,
createView: this.getItemTemplateViewFactory(template)
};
this._templateHeaderMap.set(key, keyedTemplate);
}
if (key === 'title' || key.startsWith('title-')) {
if (!this._templateItemHeaderMap) {
this._templateItemHeaderMap = new Map<string, KeyedTemplate>();
}
const keyedTemplate = {
key,
createView: this.getItemTemplateViewFactory(template)
};
this._templateItemHeaderMap.set(key, keyedTemplate);
}
if (key === 'content' || key.startsWith('content-')) {
if (!this._templateItemContentMap) {
this._templateItemContentMap = new Map<string, KeyedTemplate>();
}
const keyedTemplate = {
key,
createView: this.getChildItemTemplateViewFactory(template)
};
this._templateItemContentMap.set(key, keyedTemplate);
}
if (key === 'footer' || key.startsWith('footer-')) {
if (!this._templateFooterMap) {
this._templateFooterMap = new Map<string, KeyedTemplate>();
}
const keyedTemplate = {
key,
createView: this.getItemTemplateViewFactory(template)
};
this._templateFooterMap.set(key, keyedTemplate);
}
}
@profile
public onHeaderLoading(args: ItemEventData) {
if (!args.view && !this.headerTemplate) {
return;
}
const index = args.index;
const items = (<any>args.object).items;
const currentItem = typeof items.getItem === 'function' ? items.getItem(index) : items[index];
let viewRef: EmbeddedViewRef<ItemContext>;
if (args.view) {
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
}
if (!viewRef) {
viewRef = this.loader.createEmbeddedView(this.headerTemplate, new ItemContext(), 0);
args.view = getItemViewRoot(viewRef);
args.view[NG_VIEW] = viewRef;
}
this.setupViewRef(viewRef, currentItem, index);
this.detectChangesOnChild(viewRef, index);
}
@profile
public onItemHeaderLoading(args: ItemEventData) {
if (!args.view && !this.itemHeaderTemplate) {
return;
}
const index = args.index;
const items = (<any>args.object).items;
const currentItem = typeof items.getItem === 'function' ? items.getItem(index) : items[index];
let viewRef: EmbeddedViewRef<ItemContext>;
if (args.view) {
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
}
if (!viewRef) {
viewRef = this.loader.createEmbeddedView(this.itemHeaderTemplate, new ItemContext(), 0);
args.view = getItemViewRoot(viewRef);
args.view[NG_VIEW] = viewRef;
}
this.setupViewRef(viewRef, currentItem, index);
this.detectChangesOnChild(viewRef, index);
}
@profile
public onItemContentLoading(args: ItemEventData) {
if (!args.view && !this.itemContentTemplate) {
return;
}
const index = args.index;
const childIndex = (args as any).childIndex;
const childItems = this.accordionItemsView.childItems;
const items = (<any>args.object).items;
const currentItem = typeof items.getItem === 'function' ? items.getItem(index)[childItems][childIndex] : items[index][childItems][childIndex];
let viewRef: EmbeddedViewRef<ChildItemContext>;
if (args.view) {
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
}
if (!viewRef) {
viewRef = this.loader.createEmbeddedView(this.itemContentTemplate, new ChildItemContext(), 0);
args.view = getItemViewRoot(viewRef);
args.view[NG_VIEW] = viewRef;
}
this.setupChildViewRef(viewRef, currentItem, index, childIndex);
this.detectChangesOnChild(viewRef, index);
}
@profile
public onFooterLoading(args: ItemEventData) {
if (!args.view && !this.footerTemplate) {
return;
}
const index = args.index;
const items = (<any>args.object).items;
const currentItem = typeof items.getItem === 'function' ? items.getItem(index) : items[index];
let viewRef: EmbeddedViewRef<ItemContext>;
if (args.view) {
viewRef = args.view[NG_VIEW];
// Getting angular view from original element (in cases when ProxyViewContainer
// is used NativeScript internally wraps it in a StackLayout)
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
viewRef = args.view.getChildAt(0)[NG_VIEW];
}
}
if (!viewRef) {
viewRef = this.loader.createEmbeddedView(this.footerTemplate, new ItemContext(), 0);
args.view = getItemViewRoot(viewRef);
args.view[NG_VIEW] = viewRef;
}
this.setupViewRef(viewRef, currentItem, index);
this.detectChangesOnChild(viewRef, index);
}
public setupViewRef(viewRef: EmbeddedViewRef<ItemContext>, data: any, index: number): void {
const context = viewRef.context;
context.$implicit = data;
context.item = data;
context.index = index;
context.even = (index % 2 === 0);
context.odd = !context.even;
this.setupItemView.next({view: viewRef, data: data, index: index, context: context});
}
public setupChildViewRef(viewRef: EmbeddedViewRef<ChildItemContext>, data: any, parentIndex: number, index: number): void {
const context = viewRef.context;
context.$implicit = data;
context.item = data;
context.parentIndex = parentIndex;
context.index = index;
context.even = (index % 2 === 0);
context.odd = !context.even;
this.setupItemView.next({view: viewRef, data: data, index: index, context: context});
}
protected getItemTemplateViewFactory(template: TemplateRef<ItemContext>): () => View {
return () => {
const viewRef = this.loader.createEmbeddedView(template, new ItemContext(), 0);
const resultView = getItemViewRoot(viewRef);
resultView[NG_VIEW] = viewRef;
return resultView;
};
}
protected getChildItemTemplateViewFactory(template: TemplateRef<ChildItemContext>): () => View {
return () => {
const viewRef = this.loader.createEmbeddedView(template, new ChildItemContext(), 0);
const resultView = getItemViewRoot(viewRef);
resultView[NG_VIEW] = viewRef;
return resultView;
};
}
@profile
private detectChangesOnChild(viewRef: EmbeddedViewRef<ItemContext>, index: number) {
viewRef.markForCheck();
viewRef.detectChanges();
}
ngDoCheck() {
if (this._differ) {
const changes = this._differ.diff(this._items);
if (changes) {
this.accordionItemsView.refresh();
}
}
}
}
Example #24
Source File: dashboard.component.ts From ng-application-builder with MIT License | 4 votes |
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements AfterContentInit {
appConfiguration: AppConfiguration = new AppConfiguration();
margin = { top: 20, right: 90, bottom: 30, left: 90 };
width = 0;
height = 0;
i = 0;
duration = 750;
root: any;
tree: any;
svg: any;
treemap: any;
selectedNode: any;
selectedNodeName = '';
newNodeName = '';
name: string;
isMenuOpen = false;
showSpinner = false;
constructor(
private dataService: DataService,
public dialog: MatDialog) { }
ngAfterContentInit() {
this.appConfiguration.nodeConfiguration = new NodeConfiguration();
this.appConfiguration.nodeConfiguration.name = 'app';
this.appConfiguration.nodeConfiguration.type = NodeType.module;
this.width = 960 - this.margin.right - this.margin.left;
this.height = 500 - this.margin.top - this.margin.bottom;
console.log('initialized...');
this.svg = d3.select('svg')
.on('click', () => {
if (this.isMenuOpen) {
d3.select('#my_custom_menu')
.style('display', 'none');
this.isMenuOpen = false;
}
})
// .attr('width', this.width + this.margin.right + this.margin.left)
// .attr('height', this.height + this.margin.top + this.margin.bottom)
.attr('width', '100%')
.attr('height', this.height + this.margin.top + this.margin.bottom)
.append('g')
.attr('transform', 'translate('
+ this.margin.left + ',' + this.margin.top + ')');
// declares a tree layout and assigns the size
this.treemap = d3.tree().size([this.height, this.width]);
// Assigns parent, children, height, depth
this.root = d3.hierarchy(this.appConfiguration.nodeConfiguration, (d: any) => d.children);
this.root.x0 = this.height / 2;
this.root.y0 = 0;
this.update(this.root);
console.log(this.svg);
}
openDialog(action: string): void {
if (this.isMenuOpen) {
d3.select('#my_custom_menu')
.style('display', 'none');
this.isMenuOpen = false;
}
this.selectedNode.action = action;
const modalData = this.selectedNode as DialogData;
modalData.action = action;
const dialogRef = this.dialog.open(NewDialogComponent, {
width: '400px',
data: modalData
});
dialogRef.afterClosed().subscribe((newNode: NodeConfiguration) => {
console.log('The dialog was closed', newNode);
if (!this.selectedNode) {
alert('Please select parent node!');
}
if (!newNode) { return; }
if (action === 'create') {
const node = {
name: newNode.name,
type: newNode.type,
route: newNode.route,
parentModule: this.selectedNode.data.name,
modulePath: this.getModulePath(this.selectedNode, newNode.name),
};
const newD3Node: any = d3.hierarchy(node);
newD3Node.depth = this.selectedNode.depth + 1;
newD3Node.height = this.selectedNode.height + 1;
newD3Node.parent = this.selectedNode;
newD3Node.id = ++this.i;
if (!this.selectedNode.children) {
this.selectedNode.children = [];
this.selectedNode.data.children = [];
}
this.selectedNode.children.push(newD3Node);
this.selectedNode.data.children.push(newD3Node.data);
this.update(this.selectedNode);
} else {
// TODO: Need to loop through all children of selected node and update their modulePath, route and name
// console.log('updating existing node...');
// this.updateModulePath(newNode);
// debugger;
// this.svg.select('#text-' + this.selectedNode.id).text(this.getNodeText(newNode));
// this.updateNodeName();
}
});
}
updateModulePath(newNode: NodeConfiguration) {
const parts = newNode.modulePath.split('/');
parts[parts.length - 1] = newNode.name;
newNode.modulePath = parts.join('/');
}
update(source: any) {
// console.log(this.appConfiguration.nodeConfiguration);
// Assigns the x and y position for the nodes
const treeData = this.treemap(this.root);
// Compute the new tree layout.
const nodes = treeData.descendants();
const links = treeData.descendants().slice(1);
// Normalize for fixed-depth.
nodes.forEach((d: any) => { d.y = d.depth * 180; });
// ****************** Nodes section ***************************
// Update the nodes...
const node = this.svg.selectAll('g.node')
.data(nodes, (d: any) => d.id || (d.id = ++this.i));
// Enter any new modes at the parent's previous position.
const nodeEnter = node.enter().append('g')
.attr('class', 'node')
.attr('transform', (d: any) => {
return 'translate(' + source.y0 + ',' + source.x0 + ')';
})
.on('click', (e: any) => { this.click(e); });
// Add Circle for the nodes
nodeEnter.append('circle')
.attr('class', 'node')
.attr('r', 1e-6)
.style('fill', (d: any) => {
// return d.data.type == NodeType.module ? "black" : "white";
// return d._children ? "lightsteelblue" : "#fff";
})
.on('click', (selectedNode) => {
this.isMenuOpen = true;
this.selectedNode = selectedNode;
d3.select('#my_custom_menu')
.style('position', 'absolute')
.style('left', d3.event.clientX + 10 + 'px')
.style('top', d3.event.clientY + 10 + 'px')
.style('display', 'block');
d3.event.stopPropagation();
});
// Add labels for the nodes
nodeEnter.append('text')
.attr('dy', '.35em')
.attr('x', (d: any) => {
return d.children || d._children ? -13 : 13;
})
.attr('text-anchor', (d: any) => {
return d.children || d._children ? 'end' : 'start';
})
.attr('id', (d: any) => 'text-' + d.id)
.text((d: any) => {
return this.getNodeText(d.data);
});
// UPDATE
const nodeUpdate = nodeEnter.merge(node);
// Transition to the proper position for the node
nodeUpdate.transition()
.duration(this.duration)
.attr('transform', (d: any) => {
return 'translate(' + d.y + ',' + d.x + ')';
});
// Update the node attributes and style
nodeUpdate.select('circle.node')
.attr('r', 10)
.style('fill', (d: any) => {
// return d.data.type == NodeType.module ? "black" : "white";
return d._children ? 'lightsteelblue' : '#fff';
})
.attr('cursor', 'pointer');
// Remove any exiting nodes
const nodeExit = node.exit().transition()
.duration(this.duration)
.attr('transform', (d: any) => {
return 'translate(' + source.y + ',' + source.x + ')';
})
.remove();
// On exit reduce the node circles size to 0
nodeExit.select('circle')
.attr('r', 1e-6);
// On exit reduce the opacity of text labels
nodeExit.select('text')
.style('fill-opacity', 1e-6);
// ****************** links section ***************************
// Update the links...
const link = this.svg.selectAll('path.link')
.data(links, (d: any) => d.id);
// Enter any new links at the parent's previous position.
const linkEnter = link.enter().insert('path', 'g')
.attr('class', 'link')
.attr('d', (d: any) => {
const o = { x: source.x0, y: source.y0 };
return this.diagonal(o, o);
});
// UPDATE
const linkUpdate = linkEnter.merge(link);
// Transition back to the parent element position
linkUpdate.transition()
.duration(this.duration)
.attr('d', (d: any) => this.diagonal(d, d.parent));
// Remove any exiting links
const linkExit = link.exit().transition()
.duration(this.duration)
.attr('d', (d: any) => {
const o = { x: source.x, y: source.y };
return this.diagonal(o, o);
})
.remove();
// Store the old positions for transition.
nodes.forEach((d: any) => {
d.x0 = d.x;
d.y0 = d.y;
});
}
getNodeText(node: any) {
return node.name + ' (' + node.type + ')';
}
diagonal(s: any, d: any) {
const path = `M ${s.y} ${s.x}
C ${(s.y + d.y) / 2} ${s.x},
${(s.y + d.y) / 2} ${d.x},
${d.y} ${d.x}`;
return path;
}
click(d: any) {
this.selectedNode = d;
this.selectedNodeName = this.selectedNode.data.name;
this.svg.selectAll('circle')
.style('fill', '#fff');
this.svg.selectAll('circle')
.filter((node: any) => node.id === d.id)
.style('fill', (node: any) => {
return node.id === d.id ? 'black' : '#fff';
});
}
addNode() {
if (!this.selectedNode) {
alert('Please select parent node!');
}
const newNode = { name: this.newNodeName, type: NodeType.moduleWithRoute };
const newD3Node: any = d3.hierarchy(newNode);
newD3Node.depth = this.selectedNode.depth + 1;
newD3Node.height = this.selectedNode.height + 1;
newD3Node.parent = this.selectedNode;
newD3Node.id = ++this.i;
if (!this.selectedNode.children) {
this.selectedNode.children = [];
this.selectedNode.data.children = [];
}
this.selectedNode.children.push(newD3Node);
this.selectedNode.data.children.push(newD3Node.data);
this.update(this.selectedNode);
}
removeNode() {
const children = [];
this.selectedNode.parent.children.forEach(child => {
if (child.id !== this.selectedNode.id) {
children.push(child);
}
});
const dataChildren = [];
this.selectedNode.parent.data.children.forEach(child => {
if (child.id !== this.selectedNode.id) {
dataChildren.push(child);
}
});
this.selectedNode.parent.children = children;
this.selectedNode.parent.data.children = children;
if (this.selectedNode.parent.children.length === 0) {
delete this.selectedNode.parent.children;
}
this.update(this.selectedNode.parent);
if (this.isMenuOpen) {
d3.select('#my_custom_menu')
.style('display', 'none');
this.isMenuOpen = false;
}
}
updateNodeName() {
this.selectedNode.data.name = this.selectedNodeName;
// console.log(this.selectedNode);
this.svg.select('#text-' + this.selectedNode.id).text(this.selectedNodeName);
this.update(this.selectedNode);
}
addNodeWithComponent() {
if (!this.selectedNode) {
alert('Please select parent node!');
}
const newNode = {
name: this.newNodeName,
type: NodeType.moduleWithRoute,
// modulePath: this.selectedNode.data.name == 'app' ? '' : this.selectedNode.data.name,
modulePath: this.getModulePath(this.selectedNode, this.newNodeName),
route: this.newNodeName,
parentModule: this.selectedNode.data.name
};
const newD3Node: any = d3.hierarchy(newNode);
newD3Node.depth = this.selectedNode.depth + 1;
newD3Node.height = this.selectedNode.height + 1;
newD3Node.parent = this.selectedNode;
newD3Node.id = ++this.i;
if (!this.selectedNode.children) {
this.selectedNode.children = [];
this.selectedNode.data.children = [];
}
this.selectedNode.children.push(newD3Node);
this.selectedNode.data.children.push(newD3Node.data);
this.update(this.selectedNode);
}
getModulePath(node: any, newNodeName: string) {
// this.selectedNode.data.name == 'app' ? '' : this.selectedNode.data.name
console.log(node);
const modulePath: Array<string> = [];
modulePath.push(newNodeName);
if (node.parent && node.parent.data.name === 'app') {
modulePath.push(node.data.name);
} else {
while (node.parent && node.data.name !== 'app') {
modulePath.push(node.data.name);
node = node.parent;
}
}
if (modulePath.length === 1) {
return newNodeName;
}
const fullModulePath = modulePath.reverse().join('/');
console.log(fullModulePath);
return fullModulePath;
}
generateApp() {
this.showSpinner = true;
this.dataService.generateApp(this.appConfiguration).subscribe((response: any) => {
console.log(response);
sdk.openProject(response);
this.showSpinner = false;
}, (err) => {
this.showSpinner = false;
alert(JSON.stringify(err));
console.error(err);
});
}
downloadApp() {
this.showSpinner = true;
this.dataService.downloadApp(this.appConfiguration).subscribe((response: any) => {
saveAs(response, this.appConfiguration.name + '.zip');
console.log(response);
this.showSpinner = false;
}, (err) => {
this.showSpinner = false;
alert(JSON.stringify(err));
console.error(err);
});
}
}
Example #25
Source File: vg-player.component.ts From ngx-videogular with MIT License | 4 votes |
@Component({
selector: 'vg-player',
encapsulation: ViewEncapsulation.None,
template: `<ng-content></ng-content>`,
styles: [
`
vg-player {
font-family: 'videogular';
position: relative;
display: flex;
width: 100%;
height: 100%;
overflow: hidden;
background-color: black;
}
vg-player.fullscreen {
position: fixed;
left: 0;
top: 0;
}
vg-player.native-fullscreen.controls-hidden {
cursor: none;
}
`,
],
providers: [VgApiService, VgFullscreenApiService, VgControlsHiddenService],
})
export class VgPlayerComponent implements AfterContentInit, OnDestroy {
elem: HTMLElement;
@HostBinding('class.fullscreen') isFullscreen = false;
@HostBinding('class.native-fullscreen') isNativeFullscreen = false;
@HostBinding('class.controls-hidden') areControlsHidden = false;
@HostBinding('style.z-index') zIndex: string;
@Output() onPlayerReady: EventEmitter<VgApiService> = new EventEmitter<VgApiService>();
@Output() onMediaReady: EventEmitter<any> = new EventEmitter();
@ContentChildren(VgMediaDirective) medias: QueryList<VgMediaDirective>;
subscriptions: Subscription[] = [];
constructor(
ref: ElementRef,
public api: VgApiService,
public fsAPI: VgFullscreenApiService,
private controlsHidden: VgControlsHiddenService
) {
this.elem = ref.nativeElement;
this.api.registerElement(this.elem);
}
ngAfterContentInit() {
this.medias.toArray().forEach((media) => {
this.api.registerMedia(media);
});
this.fsAPI.init(this.elem, this.medias);
this.subscriptions.push(
this.fsAPI.onChangeFullscreen.subscribe(
this.onChangeFullscreen.bind(this)
)
);
this.subscriptions.push(
this.controlsHidden.isHidden.subscribe(this.onHideControls.bind(this))
);
this.api.onPlayerReady(this.fsAPI);
this.onPlayerReady.emit(this.api);
}
onChangeFullscreen(fsState: boolean) {
if (!this.fsAPI.nativeFullscreen) {
this.isFullscreen = fsState;
this.zIndex = fsState ? VgUtilsService.getZIndex().toString() : 'auto';
} else {
this.isNativeFullscreen = fsState;
}
}
onHideControls(hidden: boolean) {
this.areControlsHidden = hidden;
}
ngOnDestroy() {
this.subscriptions.forEach((s) => s.unsubscribe());
}
}
Example #26
Source File: toc-container.directive.ts From alauda-ui with MIT License | 4 votes |
@Directive({
selector: '[auiTocContainer]',
exportAs: 'auiTocContainer',
})
export class TocContainerDirective implements AfterContentInit, OnDestroy {
@Output()
activedChange = new EventEmitter<string>();
private _contents: TocContentDirective[] = [];
private readonly _scrollTop$ = new Subject<number>();
private readonly _scrollTo$ = new Subject<string>();
private readonly _onDestroy$ = new Subject<void>();
private readonly _subs: Subscription[] = [];
private _nativeElement: HTMLElement;
get scrollTop(): number {
return this._nativeElement.scrollTop || 0;
}
set scrollTop(value: number) {
this._nativeElement.scrollTop = value;
}
get isScrollEnd() {
return (
this._nativeElement.scrollHeight - this._nativeElement.scrollTop ===
this._nativeElement.clientHeight
);
}
constructor(
elementRef: ElementRef<HTMLElement>,
private readonly cdr: ChangeDetectorRef,
) {
this._nativeElement = elementRef.nativeElement;
}
getOffsetTop(element: HTMLElement): number {
if (element.parentElement === this._nativeElement) {
return element.offsetTop;
}
return element.offsetTop + this.getOffsetTop(element.parentElement);
}
private getMinContent(scrollTop: number) {
return (minContent: TocContentDirective, content: TocContentDirective) => {
if (
Math.abs(scrollTop - this.getOffsetTop(content.nativeElement)) <
Math.abs(scrollTop - this.getOffsetTop(minContent.nativeElement))
) {
minContent = content;
}
return minContent;
};
}
private getMaxContent(
maxContent: TocContentDirective,
content: TocContentDirective,
) {
if (
this.getOffsetTop(content.nativeElement) >
this.getOffsetTop(maxContent.nativeElement)
) {
maxContent = content;
}
return maxContent;
}
@HostListener('scroll')
onScroll() {
this._scrollTop$.next(this.scrollTop);
}
ngAfterContentInit() {
const actived$ = this._scrollTop$
.pipe(
startWith(this.scrollTop),
debounceTime(200),
map(scrollTop =>
this._contents.reduce(
this.isScrollEnd
? this.getMaxContent.bind(this)
: this.getMinContent(scrollTop),
),
),
map(actived => actived.auiTocContent),
)
.pipe(
tap(actived => {
this._contents.forEach(content => {
content.active = actived === content.auiTocContent;
});
this.cdr.detectChanges();
}),
);
const scrollTween$ = this._scrollTo$.pipe(
switchMap(name => {
const target = this._contents.find(
content => content.auiTocContent === name,
);
if (!target) {
return EMPTY;
}
const destination = this.getOffsetTop(target.nativeElement);
const start = performance.now();
const source = this.scrollTop;
const duration = 500;
return of(0).pipe(
observeOn(animationFrameScheduler),
repeat(),
map(() => (performance.now() - start) / duration),
takeWhile(t => t < 1),
endWith(1),
map(t => t * t * t),
map(t => source * (1 - t) + destination * t),
);
}),
takeUntil(this._onDestroy$),
);
this._subs.push(
actived$.subscribe(this.activedChange),
scrollTween$.subscribe(tweenValue => {
this.scrollTop = tweenValue;
}),
);
}
ngOnDestroy() {
this._subs.forEach(sub => sub.unsubscribe());
this._onDestroy$.next();
}
scrollTo(content: string | string[]) {
if (Array.isArray(content)) {
this._scrollTo$.next(content[0]);
} else {
this._scrollTo$.next(content);
}
}
registerContent(tocContent: TocContentDirective) {
this._contents = [...this._contents, tocContent];
}
deregisterContent(tocContent: TocContentDirective) {
this._contents = this._contents.filter(
content => content.auiTocContent !== tocContent.auiTocContent,
);
}
}
Example #27
Source File: accordion-item.component.ts From canopy with Apache License 2.0 | 4 votes |
@Component({
selector: 'lg-accordion-item',
templateUrl: './accordion-item.component.html',
styleUrls: [ './accordion-item.component.scss' ],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
// Do not provide LG_ACCORDION to nested accordion components
providers: [ { provide: LG_ACCORDION, useValue: undefined } ],
})
export class LgAccordionItemComponent implements AfterContentInit, OnChanges, OnDestroy {
private _toggleSubscription: Subscription;
_id = `${nextUniqueId++}`;
_toggleId = `lg-accordion-panel-heading-${this._id}`;
_panelId = `lg-accordion-panel-${this._id}`;
_showContent = false;
_contentTemplate: TemplateRef<any>;
@Input() isActive = false;
@Output() opened = new EventEmitter<void>();
@Output() closed = new EventEmitter<void>();
@ViewChild(LgAccordionItemContentDirective, { static: true })
defaultContent: LgAccordionItemContentDirective;
@ContentChild(LgAccordionItemContentDirective)
lazyContent: LgAccordionItemContentDirective;
@ContentChild(LgAccordionPanelHeadingComponent)
accordionPanelHeading: LgAccordionPanelHeadingComponent;
constructor(
@Optional() @SkipSelf() @Inject(LG_ACCORDION) public accordion: LgAccordionComponent,
private selectionDispatcher: UniqueSelectionDispatcher,
private cdr: ChangeDetectorRef,
) {
this._removeSingleItemSelectionListener = selectionDispatcher.listen(
(id: string, accordionId: string) => {
if (
accordion &&
!accordion.multi &&
accordion.id === accordionId &&
this._id !== id
) {
this.isActive = false;
this.accordionPanelHeading.isActive = false;
this.closed.emit();
this.cdr.markForCheck();
}
},
);
}
ngAfterContentInit() {
this.accordionPanelHeading.isActive = this.isActive;
this._showContent = this.isActive || !this.lazyContent;
this._contentTemplate = (this.lazyContent || this.defaultContent)._template;
if (this.isActive) {
this.toggleActiveState(this.isActive);
}
this._toggleSubscription = this.accordionPanelHeading.toggleActive.subscribe(
isActive => {
this.isActive = isActive;
this.toggleActiveState(isActive);
this.cdr.markForCheck();
},
);
}
ngOnChanges(changes: SimpleChanges) {
if (this.accordionPanelHeading && changes.isActive) {
const isActive = changes.isActive.currentValue || false;
this.accordionPanelHeading.isActive = isActive;
this.toggleActiveState(isActive);
}
}
ngOnDestroy() {
this._toggleSubscription?.unsubscribe();
this._removeSingleItemSelectionListener();
}
private toggleActiveState(isActive: boolean) {
if (isActive) {
if (!this._showContent) {
this._showContent = true;
}
this.opened.emit();
this.selectionDispatcher.notify(
this._id,
this.accordion
? this.accordion.id
: this._panelId,
);
} else {
this.closed.emit();
}
}
private readonly _removeSingleItemSelectionListener: () => void = () => {};
}
Example #28
Source File: chat.component.ts From qd-messages-ts with GNU Affero General Public License v3.0 | 4 votes |
/**
* Conversational UI collection - a set of components for chat-like UI construction.
*
* Main features:
* - different message types support (text, image, file, file group, map, etc)
* - drag & drop for images and files with preview
* - different UI styles
* - custom action buttons (coming soon)
*
* Here's a complete example build in a bot-like app. Type `help` to be able to receive different message types.
* Enjoy the conversation and the beautiful UI.
* @stacked-example(Showcase, chat/chat-showcase.component)
*
* Basic chat configuration and usage:
* ```ts
* <nb-chat title="Nebular Conversational UI">
* <nb-chat-message *ngFor="let msg of messages"
* [type]="msg.type"
* [message]="msg.text"
* [reply]="msg.reply"
* [sender]="msg.user.name"
* [date]="msg.date"
* [files]="msg.files"
* [quote]="msg.quote"
* [latitude]="msg.latitude"
* [longitude]="msg.longitude"
* [avatar]="msg.user.avatar">
* </nb-chat-message>
*
* <nb-chat-form (send)="sendMessage($event)" [dropFiles]="true">
* </nb-chat-form>
* </nb-chat>
* ```
* ### Installation
*
* Import `NbChatModule` to your feature module.
* ```ts
* @NgModule({
* imports: [
* // ...
* NbChatModule,
* ],
* })
* export class PageModule { }
* ```
*
* If you need to provide an API key for a `map` message type (which is required by Google Maps)
* you may use `NbChatModule.forRoot({ ... })` call if this is a global app configuration
* or `NbChatModule.forChild({ ... })` for a feature module configuration:
*
* ```ts
* @NgModule({
* imports: [
* // ...
* NbChatModule.forRoot({ messageGoogleMapKey: 'MAP_KEY' }),
* ],
* })
* export class AppModule { }
* ```
*
* ### Usage
*
* There are three main components:
* ```ts
* <nb-chat>
* </nb-chat> // chat container
*
* <nb-chat-form>
* </nb-chat-form> // chat form with drag&drop files feature
*
* <nb-chat-message>
* </nb-chat-message> // chat message, available multiple types
* ```
*
* Two users conversation showcase:
* @stacked-example(Conversation, chat/chat-conversation-showcase.component)
*
* Chat UI is also available in different colors by specifying a `[status]` input:
*
* @stacked-example(Colored Chat, chat/chat-colors.component)
*
* Also it is possible to configure sizes through `[size]` input:
*
* @stacked-example(Chat Sizes, chat/chat-sizes.component)
*
* @styles
*
* chat-background-color:
* chat-border:
* chat-border-radius:
* chat-shadow:
* chat-padding:
* chart-scrollbar-color:
* chart-scrollbar-background-color:
* chart-scrollbar-width:
* chat-text-color:
* chat-text-font-family:
* chat-text-font-size:
* chat-text-font-weight:
* chat-text-line-height:
* chat-header-text-color:
* chat-header-text-font-family:
* chat-header-text-font-size:
* chat-header-text-font-weight:
* chat-header-text-line-height:
* chat-tiny-height:
* chat-small-height:
* chat-medium-height:
* chat-large-height:
* chat-giant-height:
* chat-primary-background-color:
* chat-primary-text-color:
* chat-success-background-color:
* chat-success-text-color:
* chat-info-background-color:
* chat-info-text-color:
* chat-warning-background-color:
* chat-warning-text-color:
* chat-danger-background-color:
* chat-danger-text-color:
* chat-divider-color:
* chat-divider-style:
* chat-divider-width:
*/
@Component({
selector: 'nb-chat',
styleUrls: ['./chat.component.scss'],
template: `
<div class="header">{{ title }}</div>
<div class="scrollable" #scrollable>
<div class="messages">
<ng-content select="nb-chat-message"></ng-content>
<p class="no-messages" *ngIf="!messages?.length">No messages yet.</p>
</div>
</div>
<div class="form">
<ng-content select="nb-chat-form"></ng-content>
</div>
`,
})
export class NbChatComponent implements OnChanges, AfterContentInit, AfterViewInit {
@Input() title: string;
/**
* Chat size, available sizes:
* `tiny`, `small`, `medium`, `large`, `giant`
*/
@Input() size: NbComponentSize;
/**
* Chat status color (adds specific styles):
* `primary`, `success`, `info`, `warning`, `danger`
*/
@Input() status: NbComponentStatus;
/**
* Scroll chat to the bottom of the list when a new message arrives
*/
@Input()
get scrollBottom(): boolean {
return this._scrollBottom
}
set scrollBottom(value: boolean) {
this._scrollBottom = convertToBoolProperty(value);
}
protected _scrollBottom: boolean = true;
@ViewChild('scrollable', { static: false }) scrollable: ElementRef;
@ContentChildren(NbChatMessageComponent) messages: QueryList<NbChatMessageComponent>;
@ContentChild(NbChatFormComponent, { static: false }) chatForm: NbChatFormComponent;
ngOnChanges(changes: SimpleChanges) {
if ('status' in changes) {
this.updateFormStatus();
}
}
ngAfterContentInit() {
this.updateFormStatus();
}
ngAfterViewInit() {
this.messages.changes
.subscribe((messages) => {
this.messages = messages;
this.updateView();
});
this.updateView();
}
updateView() {
if (this.scrollBottom) {
this.scrollListBottom();
}
}
scrollListBottom() {
this.scrollable.nativeElement.scrollTop = this.scrollable.nativeElement.scrollHeight;
}
protected updateFormStatus(): void {
if (this.chatForm) {
this.chatForm.setStatus(this.status);
}
}
@HostBinding('class.size-tiny')
get tiny(): boolean {
return this.size === 'tiny';
}
@HostBinding('class.size-small')
get small(): boolean {
return this.size === 'small';
}
@HostBinding('class.size-medium')
get medium(): boolean {
return this.size === 'medium';
}
@HostBinding('class.size-large')
get large(): boolean {
return this.size === 'large';
}
@HostBinding('class.size-giant')
get giant(): boolean {
return this.size === 'giant';
}
@HostBinding('class.status-primary')
get primary(): boolean {
return this.status === 'primary';
}
@HostBinding('class.status-success')
get success(): boolean {
return this.status === 'success';
}
@HostBinding('class.status-info')
get info(): boolean {
return this.status === 'info';
}
@HostBinding('class.status-warning')
get warning(): boolean {
return this.status === 'warning';
}
@HostBinding('class.status-danger')
get danger(): boolean {
return this.status === 'danger';
}
}
Example #29
Source File: anchor.directive.ts From alauda-ui with MIT License | 4 votes |
@Directive({
selector: '[auiAnchor]',
})
export class AnchorDirective implements AfterContentInit, OnDestroy {
@Input()
auiAnchor: HTMLElement | '';
@Input()
adaptPosition = true;
@Input()
padding = 20;
@Input()
minTop: number;
@Input()
injectId = window === window.top;
@ContentChildren(AnchorLabelDirective, { descendants: true })
anchorLabels: QueryList<AnchorLabelDirective>;
get containerEl() {
return this.elRef.nativeElement;
}
get scrollableEl() {
const el = this.containerEl;
return (
this.auiAnchor ||
this.cdkScrollable?.getElementRef().nativeElement ||
(el.scrollHeight > el.offsetHeight ? el : window)
);
}
anchorPortal: ComponentPortal<AnchorComponent>;
destroy$$ = new Subject<void>();
constructor(
private readonly cfr: ComponentFactoryResolver,
private readonly appRef: ApplicationRef,
private readonly injector: Injector,
public readonly elRef: ElementRef<HTMLElement>,
@Optional() private readonly cdkScrollable: CdkScrollable,
) {}
ngAfterContentInit() {
const containerEl = this.containerEl;
this.anchorPortal = new ComponentPortal(AnchorComponent);
const portalOutlet = new DomPortalOutlet(
document.body,
this.cfr,
this.appRef,
this.injector,
);
const anchorComponentRef = this.anchorPortal.attach(portalOutlet);
const anchorEl = anchorComponentRef.injector.get(ElementRef)
.nativeElement as HTMLElement;
requestAnimationFrame(() =>
this.adaptAnchorPosition(containerEl, anchorEl),
);
this.anchorLabels.changes
.pipe(startWith(this.anchorLabels), takeUntil(this.destroy$$))
.subscribe((anchorLabels: QueryList<AnchorLabelDirective>) => {
Object.assign(anchorComponentRef.instance, {
items: anchorLabels.toArray(),
});
});
}
ngOnDestroy() {
this.destroy$$.next();
this.destroy$$.complete();
this.anchorPortal.detach();
}
adaptAnchorPosition(containerEl: HTMLElement, anchorEl: HTMLElement) {
const pageContentEl = containerEl.closest('.aui-page__content');
const anchorContentEl = anchorEl.querySelector('.aui-anchor');
merge(observeResizeOn(containerEl), fromEvent(window, 'scroll'))
.pipe(startWith(null as void), takeUntil(this.destroy$$))
.subscribe(() => {
const containerRect = containerEl.getBoundingClientRect();
Object.assign(anchorEl.style, {
display: !containerRect.width || !containerRect.height ? 'none' : '',
left:
containerRect.right -
anchorContentEl.getBoundingClientRect().width +
'px',
top:
Math.max(
containerRect.top,
(this.minTop ??
(pageContentEl &&
+getComputedStyle(pageContentEl).paddingTop.slice(0, -2))) ||
0,
) + 'px',
});
});
if (this.adaptPosition) {
observeResizeOn(anchorContentEl)
.pipe(takeUntil(this.destroy$$))
.subscribe(el => {
const width = el.getBoundingClientRect().width;
const padding = width + this.padding;
containerEl.style.paddingRight = padding + 'px';
});
}
}
}