Skip to content

Commit

Permalink
Merge pull request #93 from artemnih/improve
Browse files Browse the repository at this point in the history
Improve providers for overriding
  • Loading branch information
artemnih committed May 1, 2024
2 parents 24bc70c + 89424ff commit 083b22b
Show file tree
Hide file tree
Showing 20 changed files with 61 additions and 119 deletions.
19 changes: 0 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,6 @@ export class MyDataService implements IDataService<MyDataType> {
}
```

`MyDataType` can be any type of data that reflects the file or directory metadata. It can be as simple as `string` or an object with properties.
`NAME_FUNCTION` must be provided if `MyDataType` is an object. It is a function that returns the name of the file or directory, to be displayed in the UI.

Example:

```Typescript
export interface MyDataType {
name: string;
path: string;
createdOn: Date;
}

// In this case, the name function will be:
{
provide: NAME_FUNCTION,
useValue: (node: INode) => node.data['name'],
}
```

And provide the implementation:

```TypeScript
Expand Down
2 changes: 1 addition & 1 deletion projects/ngx-explorer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-explorer",
"version": "4.3.0",
"version": "4.5.0",
"peerDependencies": {
"@angular/common": "^17.2.0",
"@angular/core": "^17.2.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Directive, OnDestroy, inject } from '@angular/core';
import { Subscription } from 'rxjs';
import { INode, NgeExplorerConfig } from '../../shared/types';
import { CONFIG, NAME_FUNCTION } from '../../shared/providers';
import { CONFIG } from '../../shared/providers';
import { ExplorerService } from '../../services/explorer.service';

@Directive()
Expand All @@ -14,7 +14,6 @@ export class BaseView implements OnDestroy {

protected explorerService: ExplorerService = inject(ExplorerService);
protected config: NgeExplorerConfig = inject(CONFIG);
protected getName: (node: INode) => string = inject(NAME_FUNCTION);

constructor() {
this.subs.add(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ChangeDetectionStrategy, Component, Inject, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, Component, ViewEncapsulation, inject } from '@angular/core';
import { map } from 'rxjs';
import { INode, NgeExplorerConfig } from '../../shared/types';
import { INode } from '../../shared/types';
import { ExplorerService } from '../../services/explorer.service';
import { CONFIG, NAME_FUNCTION } from '../../shared/providers';
import { CONFIG } from '../../shared/providers';
import { AsyncPipe } from '@angular/common';

interface Breadcrumb {
Expand All @@ -20,6 +20,9 @@ interface Breadcrumb {
imports: [AsyncPipe],
})
export class BreadcrumbsComponent {
private explorerService = inject(ExplorerService);
private config = inject(CONFIG);

public breadcrumbs$ = this.explorerService.openedDir$.pipe(
map((n) => {
if (!n) {
Expand All @@ -28,20 +31,14 @@ export class BreadcrumbsComponent {
const pieces = [] as Breadcrumb[];
let currentNode = n;
while (currentNode.parentId) {
pieces.unshift({ name: this.getName(currentNode) || this.config.homeNodeName || '', node: currentNode });
pieces.unshift({ name: currentNode.name || this.config.homeNodeName || '', node: currentNode });
currentNode = this.explorerService.getNode(currentNode.parentId);
}
pieces.unshift({ name: this.getName(currentNode) || this.config.homeNodeName || '', node: currentNode });
pieces.unshift({ name: currentNode.name || this.config.homeNodeName || '', node: currentNode });
return pieces;
})
);

constructor(
private explorerService: ExplorerService,
@Inject(NAME_FUNCTION) private getName: (node: INode) => string,
@Inject(CONFIG) private config: NgeExplorerConfig
) {}

public click(crumb: Breadcrumb) {
this.explorerService.openNode(crumb.node.id);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { AsyncPipe, NgComponentOutlet } from '@angular/common';
import { Component, Inject } from '@angular/core';
import { Component, inject } from '@angular/core';
import { IconsComponent } from '../icons/icons.component';
import { ListComponent } from '../list/list.component';
import { MenuBarComponent } from '../menu-bar/menu-bar.component';
import { TreeComponent } from '../tree/tree.component';
import { map, BehaviorSubject } from 'rxjs';
import { CURRENT_VIEW, VIEWS } from '../../shared/providers';
import { View } from '../../shared/types';
import { VIEWS } from '../../shared/providers';
import { BreadcrumbsComponent } from '../breadcrumbs/breadcrumbs.component';
import { ExplorerService } from '../../services/explorer.service';
import { map } from 'rxjs';

@Component({
selector: 'nxe-content',
Expand All @@ -17,10 +17,7 @@ import { BreadcrumbsComponent } from '../breadcrumbs/breadcrumbs.component';
styleUrl: './content.component.scss',
})
export class ContentComponent {
public viewComponent$ = this.currentView$.pipe(map((view) => this.views.find((v) => v.name === view)!.component));

constructor(
@Inject(CURRENT_VIEW) private currentView$: BehaviorSubject<string>,
@Inject(VIEWS) protected views: View[]
) {}
protected explorerService = inject(ExplorerService);
protected views = inject(VIEWS);
public viewComponent$ = this.explorerService.currentView$.pipe(map((view) => this.views.find((v) => v.name === view)!.component));
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
<div class="nxe-icons-container">
@for (item of items; track $index) {
<div class="nxe-icons-wrapper" (dblclick)="open($event, item)" (click)="select($event, item)">
<div class="nxe-icons-wrapper-inner" [ngClass]="{ 'nxe-icon-selected': isSelected(item) }" [title]="getName(item)">
<div class="nxe-icons-wrapper-inner" [ngClass]="{ 'nxe-icon-selected': isSelected(item) }" [title]="item.name">
<div class="nxe-icons-icon">
<i [className]="item.isLeaf ? icons.leaf : icons.node"></i>
</div>
<div class="nxe-icon-text">{{ getName(item) }}</div>
<div class="nxe-icon-text">{{ item.name }}</div>
</div>
</div>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<span class="nxe-list-icon">
<i [className]="item.isLeaf ? icons.leaf : icons.node"></i>
</span>
{{ getName(item) }}
{{ item.name }}
</td>
<td></td>
<td></td>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Component, ElementRef, ViewChild, ViewEncapsulation, inject } from '@angular/core';
import { map, take } from 'rxjs';
import { INode, NgeExplorerConfig } from '../../shared/types';
import { NgeExplorerConfig } from '../../shared/types';
import { ExplorerService } from '../../services/explorer.service';
import { ViewSwitcherComponent } from '../view-switcher/view-switcher.component';
import { CONFIG, NAME_FUNCTION } from '../../shared/providers';
import { CONFIG } from '../../shared/providers';
import { AsyncPipe } from '@angular/common';

@Component({
Expand All @@ -18,7 +18,6 @@ export class MenuBarComponent {
@ViewChild('uploader', { static: true }) uploader!: ElementRef;

protected explorerService: ExplorerService = inject(ExplorerService);
protected getName: (node: INode) => string = inject(NAME_FUNCTION);
protected config: NgeExplorerConfig = inject(CONFIG);

protected featDelete = this.config.features?.delete;
Expand Down Expand Up @@ -49,7 +48,7 @@ export class MenuBarComponent {
map((n) => n[0])
)
.subscribe((node) => {
const oldName = this.getName(node);
const oldName = node.name;
const newName = prompt('Enter new name', oldName);
if (newName) {
this.explorerService.rename(newName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<div class="chevron" (click)="collapse(node)"><i class="nxe-angle-down" aria-hidden="true"></i></div>
}
<div class="dir-icon"><i class="nxe-folder" aria-hidden="true"></i></div>
<div class="dir-name" [innerText]="getName(node)"></div>
<div class="dir-name" [innerText]="node.name"></div>
</div>

<ng-container *ngTemplateOutlet="tree; context: { nodes: node.children }"> </ng-container>
Expand Down
12 changes: 5 additions & 7 deletions projects/ngx-explorer/src/lib/components/tree/tree.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Component, Inject, OnDestroy, ViewEncapsulation } from '@angular/core';
import { Component, OnDestroy, ViewEncapsulation, inject } from '@angular/core';
import { ExplorerService } from '../../services/explorer.service';
import { filter } from 'rxjs/operators';
import { Subscription } from 'rxjs';
import { INode } from '../../shared/types';
import { NgClass, NgTemplateOutlet } from '@angular/common';
import { NAME_FUNCTION } from '../../shared/providers';

@Component({
selector: 'nxe-tree',
Expand All @@ -15,15 +14,13 @@ import { NAME_FUNCTION } from '../../shared/providers';
imports: [NgTemplateOutlet, NgClass],
})
export class TreeComponent implements OnDestroy {
private explorerService = inject(ExplorerService);
protected treeNodes: INode[] = [];
protected expnadedIds = new Set<number>();
protected selectedId = -1;
private sub = new Subscription();

constructor(
private explorerService: ExplorerService,
@Inject(NAME_FUNCTION) protected getName: (node: INode) => string
) {
constructor() {
this.sub.add(
this.explorerService.root$.pipe(filter((x) => !!x)).subscribe((root) => {
this.expnadedIds.add(root.id); // always expand root
Expand Down Expand Up @@ -57,9 +54,10 @@ export class TreeComponent implements OnDestroy {
}

private buildTree(node: INode): INode {
const { id, parentId, data, isLeaf, children } = node;
const { id, parentId, name, data, isLeaf, children } = node;
const treeNode = {
id,
name: name,
parentId,
data,
isLeaf,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component, Inject, ViewEncapsulation } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { View } from '../../shared/types';
import { CURRENT_VIEW, VIEWS } from '../../shared/providers';
import { Component, ViewEncapsulation, inject } from '@angular/core';
import { VIEWS } from '../../shared/providers';
import { ExplorerService } from '../../services/explorer.service';

@Component({
selector: 'nxe-view-switcher',
Expand All @@ -11,12 +10,10 @@ import { CURRENT_VIEW, VIEWS } from '../../shared/providers';
standalone: true,
})
export class ViewSwitcherComponent {
constructor(
@Inject(CURRENT_VIEW) private currentView: BehaviorSubject<string>,
@Inject(VIEWS) protected views: View[]
) {}
private explorerService = inject(ExplorerService);
protected views = inject(VIEWS);

setView(view: string) {
this.currentView.next(view);
this.explorerService.currentView$.next(view);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';
import { Directive, EventEmitter, HostListener, Output, inject } from '@angular/core';
import { ExplorerService } from '../services/explorer.service';

@Directive({
selector: '[nxeDragDrop]',
standalone: true,
})
export class DragDropDirective {
private explorerService = inject(ExplorerService);
@Output() dragEnter = new EventEmitter<any>();
@Output() dragOver = new EventEmitter<any>();
@Output() dragLeave = new EventEmitter<any>();
@Output() dragDrop = new EventEmitter<any>();
@Output() dragging = new EventEmitter<boolean>();

constructor(private explorerService: ExplorerService) {}

@HostListener('dragenter', ['$event'])
public onDragEnter(event: DragEvent) {
event.preventDefault();
Expand Down
1 change: 1 addition & 0 deletions projects/ngx-explorer/src/lib/services/data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export abstract class DataService implements IDataService<Data> {
abstract delete(data: Data[]): Observable<Data>;
abstract uploadFiles(data: Data, files: FileList): Observable<Data>;
abstract downloadFile(data: Data): Observable<Data>;
abstract getName(data: Data): string;
}
27 changes: 11 additions & 16 deletions projects/ngx-explorer/src/lib/services/explorer.service.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { Inject, Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { tap } from 'rxjs/operators';
import { INode, Dictionary, NgeExplorerConfig } from '../shared/types';
import { INode, Dictionary } from '../shared/types';
import { Utils } from '../shared/utils';
import { DataService } from './data.service';
import { CONFIG } from '../shared/providers';
import { CONFIG, VIEWS } from '../shared/providers';

@Injectable({
providedIn: 'root',
})
export class ExplorerService {
private internalTree = Utils.createNode();
private dataService = inject(DataService);
private config = inject(CONFIG);
private views = inject(VIEWS);
private internalTree = Utils.createNode(this.config.homeNodeName || 'Home');
private flatPointers: Dictionary<INode> = { [this.internalTree.id]: this.internalTree };

private readonly selectedNodes$$ = new BehaviorSubject<INode[]>([]);
private readonly openedNode$$ = new BehaviorSubject<INode | undefined>(undefined);
private readonly root$$ = new BehaviorSubject<INode>(this.internalTree);
public readonly currentView$ = new BehaviorSubject<string>(this.config.defaultView || this.views[0].name);

/**
* An Observable that emits the currently selected nodes in the explorer.
Expand All @@ -35,17 +39,8 @@ export class ExplorerService {
*/
public readonly root$ = this.root$$.asObservable();

constructor(
private dataService: DataService,
@Inject(CONFIG) private config: NgeExplorerConfig
) {
constructor() {
this.openNode(this.internalTree.id);

if (this.config.autoRefresh) {
setInterval(() => {
this.refresh();
}, this.config.autoRefreshInterval);
}
}

/**
Expand Down Expand Up @@ -190,8 +185,8 @@ export class ExplorerService {

return this.dataService.getContent(parent.data).pipe(
tap(({ files, dirs }) => {
const newDirNodes = dirs.map((data) => Utils.createNode(id, false, data));
const newFileNodes = files.map((data) => Utils.createNode(id, true, data));
const newDirNodes = dirs.map((data) => Utils.createNode(this.dataService.getName(data), id, false, data));
const newFileNodes = files.map((data) => Utils.createNode(this.dataService.getName(data), id, true, data));
const newChildren = newDirNodes.concat(newFileNodes);
const added = newChildren.filter((c) => !parent.children.find((o) => Utils.compareObjects(o.data, c.data)));
const removed = parent.children.filter((o) => !newChildren.find((c) => Utils.compareObjects(o.data, c.data)));
Expand Down
20 changes: 1 addition & 19 deletions projects/ngx-explorer/src/lib/shared/providers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { InjectionToken, inject } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { INode, NgeExplorerConfig, View } from './types';
import { Data, NgeExplorerConfig, View } from './types';
import { IconsComponent, ListComponent } from '../../public-api';

export const DEFAULT_CONFIG: Partial<NgeExplorerConfig> = {
homeNodeName: 'Files',
autoRefresh: false,
autoRefreshInterval: 10000,
multipleSelection: true,
features: {
delete: true,
Expand Down Expand Up @@ -41,18 +38,3 @@ export const CONFIG = new InjectionToken<NgeExplorerConfig>('NXE_CONFIG', {
return { ...DEFAULT_CONFIG, defaultView } as NgeExplorerConfig;
},
});

export const CURRENT_VIEW = new InjectionToken<BehaviorSubject<string>>('NXE_CURRENT_VIEW', {
providedIn: 'root',
factory: () => {
const config = inject(CONFIG);
const views = inject(VIEWS);
const defaultView = config.defaultView || views[0].name;
return new BehaviorSubject<string>(defaultView);
},
});

export const NAME_FUNCTION = new InjectionToken<(node: INode) => string>('NXE_NAME_FUNCTION', {
providedIn: 'root',
factory: () => (node: INode) => node.data as unknown as string,
});
3 changes: 1 addition & 2 deletions projects/ngx-explorer/src/lib/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Data {

export interface INode {
id: number;
name: string;
parentId: number;
data: Data;
isLeaf: boolean;
Expand Down Expand Up @@ -61,8 +62,6 @@ export interface View {

export interface NgeExplorerConfig {
homeNodeName: string;
autoRefresh?: boolean;
autoRefreshInterval?: number;
defaultView: string;
multipleSelection?: boolean;
features?: {
Expand Down
Loading

0 comments on commit 083b22b

Please sign in to comment.