diff --git a/lib/content-services/dialogs/dialog.module.ts b/lib/content-services/dialogs/dialog.module.ts
index 2b30def510..79fa316e80 100644
--- a/lib/content-services/dialogs/dialog.module.ts
+++ b/lib/content-services/dialogs/dialog.module.ts
@@ -21,7 +21,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CoreModule } from '@alfresco/adf-core';
import { MaterialModule } from '../material.module';
-import { DownloadZipDialogComponent } from './download-zip.dialog';
import { FolderDialogComponent } from './folder.dialog';
import { NodeLockDialogComponent } from './node-lock.dialog';
import { ConfirmDialogComponent } from './confirm.dialog';
@@ -40,21 +39,18 @@ import { LibraryDialogComponent } from './library/library.dialog';
MatDatetimepickerModule
],
declarations: [
- DownloadZipDialogComponent,
FolderDialogComponent,
NodeLockDialogComponent,
ConfirmDialogComponent,
LibraryDialogComponent
],
exports: [
- DownloadZipDialogComponent,
FolderDialogComponent,
NodeLockDialogComponent,
ConfirmDialogComponent,
LibraryDialogComponent
],
entryComponents: [
- DownloadZipDialogComponent,
FolderDialogComponent,
NodeLockDialogComponent,
ConfirmDialogComponent,
diff --git a/lib/content-services/dialogs/public-api.ts b/lib/content-services/dialogs/public-api.ts
index 6ff9033c9b..a28149ce72 100644
--- a/lib/content-services/dialogs/public-api.ts
+++ b/lib/content-services/dialogs/public-api.ts
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-export * from './download-zip.dialog';
export * from './folder.dialog';
export * from './node-lock.dialog';
export * from './confirm.dialog';
diff --git a/lib/content-services/directives/content-directive.module.ts b/lib/content-services/directives/content-directive.module.ts
index 1a51d261d9..61487bee88 100644
--- a/lib/content-services/directives/content-directive.module.ts
+++ b/lib/content-services/directives/content-directive.module.ts
@@ -19,7 +19,6 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MaterialModule } from '../material.module';
-import { NodeDownloadDirective } from './node-download.directive';
import { NodeLockDirective } from './node-lock.directive';
@NgModule({
@@ -28,11 +27,9 @@ import { NodeLockDirective } from './node-lock.directive';
MaterialModule
],
declarations: [
- NodeDownloadDirective,
NodeLockDirective
],
exports: [
- NodeDownloadDirective,
NodeLockDirective
]
})
diff --git a/lib/content-services/directives/public-api.ts b/lib/content-services/directives/public-api.ts
index 1df33c4d8b..5873bf189e 100644
--- a/lib/content-services/directives/public-api.ts
+++ b/lib/content-services/directives/public-api.ts
@@ -15,6 +15,4 @@
* limitations under the License.
*/
-export * from './node-download.directive';
-
export * from './content-directive.module';
diff --git a/lib/content-services/document-list/services/node-actions.service.ts b/lib/content-services/document-list/services/node-actions.service.ts
index 40bc084818..c256d249b5 100644
--- a/lib/content-services/document-list/services/node-actions.service.ts
+++ b/lib/content-services/document-list/services/node-actions.service.ts
@@ -18,12 +18,11 @@
import { Injectable, Output, EventEmitter } from '@angular/core';
import { MinimalNodeEntryEntity, MinimalNodeEntity } from 'alfresco-js-api';
import { Subject } from 'rxjs';
-import { AlfrescoApiService, ContentService } from '@alfresco/adf-core';
+import { AlfrescoApiService, ContentService, NodeDownloadDirective } from '@alfresco/adf-core';
import { MatDialog } from '@angular/material';
import { DocumentListService } from './document-list.service';
import { ContentNodeDialogService } from '../../content-node-selector/content-node-dialog.service';
-import { NodeDownloadDirective } from '../../directives/node-download.directive';
@Injectable({
providedIn: 'root'
diff --git a/lib/core/core.module.ts b/lib/core/core.module.ts
index 955fb1141c..e2faca214a 100644
--- a/lib/core/core.module.ts
+++ b/lib/core/core.module.ts
@@ -45,6 +45,7 @@ import { TemplateModule } from './templates/template.module';
import { ClipboardModule } from './clipboard/clipboard.module';
import { DirectiveModule } from './directives/directive.module';
+import { DialogModule } from './dialogs/dialog.module';
import { PipeModule } from './pipes/pipe.module';
import { AlfrescoApiService } from './services/alfresco-api.service';
@@ -66,6 +67,7 @@ export function createTranslateLoader(http: HttpClient) {
PipeModule,
CommonModule,
DirectiveModule,
+ DialogModule,
ClipboardModule,
FormsModule,
ReactiveFormsModule,
@@ -103,6 +105,7 @@ export function createTranslateLoader(http: HttpClient) {
PipeModule,
CommonModule,
DirectiveModule,
+ DialogModule,
ClipboardModule,
FormsModule,
ReactiveFormsModule,
@@ -139,6 +142,7 @@ export class CoreModuleLazy {
PipeModule,
CommonModule,
DirectiveModule,
+ DialogModule,
FormsModule,
ReactiveFormsModule,
HttpClientModule,
@@ -175,6 +179,7 @@ export class CoreModuleLazy {
PipeModule,
CommonModule,
DirectiveModule,
+ DialogModule,
ClipboardModule,
FormsModule,
ReactiveFormsModule,
diff --git a/lib/core/dialogs/dialog.module.ts b/lib/core/dialogs/dialog.module.ts
new file mode 100755
index 0000000000..5ca8401801
--- /dev/null
+++ b/lib/core/dialogs/dialog.module.ts
@@ -0,0 +1,43 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+
+import { MaterialModule } from '../material.module';
+import { DownloadZipDialogComponent } from './download-zip.dialog';
+import { TranslateModule } from '@ngx-translate/core';
+import { PipeModule } from '../pipes/pipe.module';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ MaterialModule,
+ TranslateModule.forChild(),
+ PipeModule
+ ],
+ declarations: [
+ DownloadZipDialogComponent
+ ],
+ exports: [
+ DownloadZipDialogComponent
+ ],
+ entryComponents: [
+ DownloadZipDialogComponent
+ ]
+})
+export class DialogModule {}
diff --git a/lib/content-services/dialogs/download-zip.dialog.html b/lib/core/dialogs/download-zip.dialog.html
old mode 100644
new mode 100755
similarity index 79%
rename from lib/content-services/dialogs/download-zip.dialog.html
rename to lib/core/dialogs/download-zip.dialog.html
index 88a9231fa9..5ad3014ab5
--- a/lib/content-services/dialogs/download-zip.dialog.html
+++ b/lib/core/dialogs/download-zip.dialog.html
@@ -4,7 +4,7 @@
-
diff --git a/lib/content-services/dialogs/download-zip.dialog.scss b/lib/core/dialogs/download-zip.dialog.scss
old mode 100644
new mode 100755
similarity index 100%
rename from lib/content-services/dialogs/download-zip.dialog.scss
rename to lib/core/dialogs/download-zip.dialog.scss
diff --git a/lib/core/dialogs/download-zip.dialog.spec.ts b/lib/core/dialogs/download-zip.dialog.spec.ts
new file mode 100755
index 0000000000..e55ff45570
--- /dev/null
+++ b/lib/core/dialogs/download-zip.dialog.spec.ts
@@ -0,0 +1,149 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { TestBed } from '@angular/core/testing';
+import { ComponentFixture } from '@angular/core/testing';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { DownloadZipDialogComponent } from './download-zip.dialog';
+import { setupTestBed } from '../testing/setupTestBed';
+import { CoreTestingModule } from '../testing/core.testing.module';
+import { DownloadZipService } from '../services/download-zip.service';
+import { of } from 'rxjs';
+
+describe('DownloadZipDialogComponent', () => {
+
+ let fixture: ComponentFixture;
+ let component: DownloadZipDialogComponent;
+ let element: HTMLElement;
+ let downloadZipService: DownloadZipService;
+ let dialogRef = {
+ close: jasmine.createSpy('close')
+ };
+
+ let dataMock = {
+ nodeIds: [
+ '123'
+ ]
+ };
+
+ let pendingDownloadEntry = {
+ entry: {
+ bytesAdded: 0,
+ filesAdded: 0,
+ id: '5bfb0907',
+ status: 'PENDING',
+ totalBytes: 0,
+ totalFiles: 0
+ }
+ };
+
+ setupTestBed({
+ imports: [CoreTestingModule],
+ providers: [
+ { provide: MatDialogRef, useValue: dialogRef },
+ { provide: MAT_DIALOG_DATA, useValue: dataMock }
+ ]
+ });
+
+ beforeEach(() => {
+ dialogRef.close.calls.reset();
+ fixture = TestBed.createComponent(DownloadZipDialogComponent);
+ downloadZipService = TestBed.get(DownloadZipService);
+ component = fixture.componentInstance;
+ element = fixture.nativeElement;
+ });
+
+ afterEach(() => {
+ fixture.destroy();
+ });
+
+ it('should call downloadZip when it is not cancelled', () => {
+ component.cancelled = false;
+ spyOn(component, 'downloadZip');
+
+ component.ngOnInit();
+
+ expect(component.downloadZip).toHaveBeenCalledWith(['123']);
+ });
+
+ it('should not call downloadZip when it is cancelled', () => {
+ component.cancelled = true;
+ spyOn(component, 'downloadZip');
+
+ component.ngOnInit();
+
+ expect(component.downloadZip).not.toHaveBeenCalled();
+ });
+
+ it('should not call downloadZip when it contains zero nodeIds', () => {
+ component.data = {
+ nodeIds: []
+ };
+ spyOn(component, 'downloadZip');
+
+ component.ngOnInit();
+
+ expect(component.downloadZip).not.toHaveBeenCalled();
+ });
+
+ it('should call cancelDownload when CANCEL button is clicked', () => {
+ fixture.detectChanges();
+ spyOn(component, 'cancelDownload').and.callThrough();
+
+ const cancelButton: HTMLButtonElement = element.querySelector('#cancel-button');
+ cancelButton.click();
+
+ expect(component.cancelDownload).toHaveBeenCalled();
+ });
+
+ it('should call createDownload when component is initialize', () => {
+ const createDownloadSpy = spyOn(downloadZipService, 'createDownload').and.returnValue(of(pendingDownloadEntry));
+ fixture.detectChanges();
+ expect(createDownloadSpy).toHaveBeenCalled();
+ });
+
+ it('should close dialog when download is completed', () => {
+ component.download('fakeUrl', 'fileName');
+ spyOn(downloadZipService, 'cancelDownload');
+ fixture.detectChanges();
+ expect(dialogRef.close).toHaveBeenCalled();
+ });
+
+ it('should close dialog when download is cancelled', () => {
+ fixture.detectChanges();
+ component.download('url', 'filename');
+ spyOn(downloadZipService, 'cancelDownload');
+ component.cancelDownload();
+ expect(dialogRef.close).toHaveBeenCalled();
+ });
+
+ it('should interrupt download when cancel button is clicked', () => {
+ spyOn(component, 'downloadZip');
+ spyOn(component, 'download');
+ spyOn(component, 'cancelDownload').and.callThrough();
+
+ fixture.detectChanges();
+
+ expect(component.downloadZip).toHaveBeenCalled();
+
+ const cancelButton: HTMLButtonElement = element.querySelector('#cancel-button');
+ cancelButton.click();
+
+ expect(component.cancelDownload).toHaveBeenCalled();
+ expect(component.download).not.toHaveBeenCalled();
+ });
+});
diff --git a/lib/content-services/dialogs/download-zip.dialog.ts b/lib/core/dialogs/download-zip.dialog.ts
old mode 100644
new mode 100755
similarity index 72%
rename from lib/content-services/dialogs/download-zip.dialog.ts
rename to lib/core/dialogs/download-zip.dialog.ts
index 8ecf77f013..1c6a321438
--- a/lib/content-services/dialogs/download-zip.dialog.ts
+++ b/lib/core/dialogs/download-zip.dialog.ts
@@ -18,7 +18,8 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { DownloadEntry, MinimalNodeEntity } from 'alfresco-js-api';
-import { LogService, AlfrescoApiService } from '@alfresco/adf-core';
+import { LogService } from '../services/log.service';
+import { DownloadZipService } from '../services/download-zip.service';
@Component({
selector: 'adf-download-zip-dialog',
@@ -30,12 +31,14 @@ import { LogService, AlfrescoApiService } from '@alfresco/adf-core';
export class DownloadZipDialogComponent implements OnInit {
// flag for async threads
- private cancelled = false;
+ cancelled = false;
+ downloadId: string;
- constructor(private apiService: AlfrescoApiService,
- private dialogRef: MatDialogRef,
- @Inject(MAT_DIALOG_DATA) private data: any,
- private logService: LogService) {
+ constructor(private dialogRef: MatDialogRef,
+ @Inject(MAT_DIALOG_DATA)
+ public data: any,
+ private logService: LogService,
+ private downloadZipService: DownloadZipService) {
}
ngOnInit() {
@@ -50,25 +53,21 @@ export class DownloadZipDialogComponent implements OnInit {
cancelDownload() {
this.cancelled = true;
+ this.downloadZipService.cancelDownload(this.downloadId);
this.dialogRef.close(false);
}
downloadZip(nodeIds: string[]) {
if (nodeIds && nodeIds.length > 0) {
- const promise: any = this.apiService.getInstance().core.downloadsApi.createDownload({ nodeIds });
-
- promise.on('progress', (progress) => this.logService.log('Progress', progress));
- promise.on('error', (error) => this.logService.error('Error', error));
- promise.on('abort', (data) => this.logService.log('Abort', data));
-
- promise.on('success', (data: DownloadEntry) => {
+ this.downloadZipService.createDownload({ nodeIds }).subscribe((data: DownloadEntry) => {
if (data && data.entry && data.entry.id) {
- const url = this.apiService.getInstance().content.getContentUrl(data.entry.id, true);
+ const url = this.downloadZipService.getContentUrl(data.entry.id, true);
- this.apiService.getInstance().core.nodesApi.getNode(data.entry.id).then((downloadNode: MinimalNodeEntity) => {
+ this.downloadZipService.getNode(data.entry.id).subscribe((downloadNode: MinimalNodeEntity) => {
this.logService.log(downloadNode);
const fileName = downloadNode.entry.name;
+ this.downloadId = data.entry.id;
this.waitAndDownload(data.entry.id, url, fileName);
});
}
@@ -81,7 +80,7 @@ export class DownloadZipDialogComponent implements OnInit {
return;
}
- this.apiService.getInstance().core.downloadsApi.getDownload(downloadId).then((downloadEntry: DownloadEntry) => {
+ this.downloadZipService.getDownload(downloadId).subscribe((downloadEntry: DownloadEntry) => {
if (downloadEntry.entry) {
if (downloadEntry.entry.status === 'DONE') {
this.download(url, fileName);
diff --git a/lib/core/dialogs/index.ts b/lib/core/dialogs/index.ts
new file mode 100755
index 0000000000..4c6ac1d58f
--- /dev/null
+++ b/lib/core/dialogs/index.ts
@@ -0,0 +1,18 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './public-api';
diff --git a/lib/core/dialogs/public-api.ts b/lib/core/dialogs/public-api.ts
new file mode 100755
index 0000000000..01b43a0623
--- /dev/null
+++ b/lib/core/dialogs/public-api.ts
@@ -0,0 +1,20 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './download-zip.dialog';
+
+export * from './dialog.module';
diff --git a/lib/core/directives/directive.module.ts b/lib/core/directives/directive.module.ts
index 3f260652f3..65298e8b6e 100644
--- a/lib/core/directives/directive.module.ts
+++ b/lib/core/directives/directive.module.ts
@@ -26,6 +26,7 @@ import { NodeFavoriteDirective } from './node-favorite.directive';
import { NodePermissionDirective } from './node-permission.directive';
import { NodeRestoreDirective } from './node-restore.directive';
import { UploadDirective } from './upload.directive';
+import { NodeDownloadDirective } from './node-download.directive';
@NgModule({
imports: [
@@ -39,6 +40,7 @@ import { UploadDirective } from './upload.directive';
NodeFavoriteDirective,
NodePermissionDirective,
NodeRestoreDirective,
+ NodeDownloadDirective,
UploadDirective
],
exports: [
@@ -48,6 +50,7 @@ import { UploadDirective } from './upload.directive';
NodeFavoriteDirective,
NodePermissionDirective,
NodeRestoreDirective,
+ NodeDownloadDirective,
UploadDirective
]
})
diff --git a/lib/content-services/directives/node-download.directive.spec.ts b/lib/core/directives/node-download.directive.spec.ts
old mode 100644
new mode 100755
similarity index 95%
rename from lib/content-services/directives/node-download.directive.spec.ts
rename to lib/core/directives/node-download.directive.spec.ts
index 2fe26f68b7..4e56e82e92
--- a/lib/content-services/directives/node-download.directive.spec.ts
+++ b/lib/core/directives/node-download.directive.spec.ts
@@ -19,9 +19,11 @@ import { TestBed, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MatDialog } from '@angular/material';
import { Component, DebugElement } from '@angular/core';
-import { AlfrescoApiService, setupTestBed, CoreModule, AlfrescoApiServiceMock } from '@alfresco/adf-core';
-
+import { setupTestBed } from '../testing/setupTestBed';
+import { CoreModule } from '../core.module';
import { DialogModule } from '../dialogs/dialog.module';
+import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
+import { AlfrescoApiService } from '../services/alfresco-api.service';
import { NodeDownloadDirective } from './node-download.directive';
@Component({
@@ -47,11 +49,9 @@ describe('NodeDownloadDirective', () => {
],
providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
- // { provide: AppConfigService, useValue: AppConfigServiceMock },
],
declarations: [
- TestComponent,
- NodeDownloadDirective
+ TestComponent
]
});
diff --git a/lib/content-services/directives/node-download.directive.ts b/lib/core/directives/node-download.directive.ts
old mode 100644
new mode 100755
similarity index 83%
rename from lib/content-services/directives/node-download.directive.ts
rename to lib/core/directives/node-download.directive.ts
index a5e38c1ec9..531747c394
--- a/lib/content-services/directives/node-download.directive.ts
+++ b/lib/core/directives/node-download.directive.ts
@@ -17,10 +17,9 @@
import { Directive, Input, HostListener } from '@angular/core';
import { MatDialog } from '@angular/material';
-import { MinimalNodeEntity } from 'alfresco-js-api';
-import { AlfrescoApiService } from '@alfresco/adf-core';
-
+import { AlfrescoApiService } from '../services/alfresco-api.service';
import { DownloadZipDialogComponent } from '../dialogs/download-zip.dialog';
+import { MinimalNodeEntity } from 'alfresco-js-api';
@Directive({
selector: '[adfNodeDownload]'
@@ -30,7 +29,7 @@ export class NodeDownloadDirective {
/** Nodes to download. */
// tslint:disable-next-line:no-input-rename
@Input('adfNodeDownload')
- nodes: MinimalNodeEntity[];
+ nodes: MinimalNodeEntity | MinimalNodeEntity[];
@HostListener('click')
onClick() {
@@ -47,15 +46,19 @@ export class NodeDownloadDirective {
* Packs result into a .ZIP archive if there is more than one node selected.
* @param selection Multiple selected nodes to download
*/
- downloadNodes(selection: Array) {
- if (!selection || selection.length === 0) {
+ downloadNodes(selection: MinimalNodeEntity | Array) {
+
+ if (!this.isSelectionValid(selection)) {
return;
}
-
- if (selection.length === 1) {
- this.downloadNode(selection[0]);
+ if (selection instanceof Array) {
+ if (selection.length === 1) {
+ this.downloadNode(selection[0]);
+ } else {
+ this.downloadZip(selection);
+ }
} else {
- this.downloadZip(selection);
+ this.downloadNode(selection);
}
}
@@ -83,6 +86,10 @@ export class NodeDownloadDirective {
}
}
+ private isSelectionValid(selection: MinimalNodeEntity | Array) {
+ return selection || (selection instanceof Array && selection.length > 0);
+ }
+
private downloadFile(node: MinimalNodeEntity) {
if (node && node.entry) {
const contentApi = this.apiService.getInstance().content;
diff --git a/lib/core/directives/public-api.ts b/lib/core/directives/public-api.ts
index da1370d4af..5a70ff3029 100644
--- a/lib/core/directives/public-api.ts
+++ b/lib/core/directives/public-api.ts
@@ -21,6 +21,7 @@ export * from './node-delete.directive';
export * from './node-favorite.directive';
export * from './node-permission.directive';
export * from './node-restore.directive';
+export * from './node-download.directive';
export * from './upload.directive';
export * from './directive.module';
diff --git a/lib/core/index.ts b/lib/core/index.ts
index bfae4e1cd1..8719abdd89 100644
--- a/lib/core/index.ts
+++ b/lib/core/index.ts
@@ -39,6 +39,7 @@ export * from './pipes/index';
export * from './services/index';
export * from './directives/index';
export * from './clipboard/index';
+export * from './dialogs/index';
export * from './utils/index';
export * from './interface/index';
diff --git a/lib/core/services/download-zip.service.ts b/lib/core/services/download-zip.service.ts
new file mode 100755
index 0000000000..7b0e9b7bd7
--- /dev/null
+++ b/lib/core/services/download-zip.service.ts
@@ -0,0 +1,60 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { NodeEntry, DownloadEntry, DownloadBodyCreate } from 'alfresco-js-api';
+import { Injectable } from '@angular/core';
+import { Observable, from, throwError } from 'rxjs';
+import { LogService } from './log.service';
+import { AlfrescoApiService } from './alfresco-api.service';
+import { catchError } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DownloadZipService {
+
+ constructor(private apiService: AlfrescoApiService,
+ private logService: LogService) {
+ }
+
+ createDownload(payload: DownloadBodyCreate): Observable {
+ return from(this.apiService.getInstance().core.downloadsApi.createDownload(payload)).pipe(
+ catchError((err) => this.handleError(err))
+ );
+ }
+
+ getContentUrl(nodeId: string, attachment?: boolean): string {
+ return this.apiService.getInstance().content.getContentUrl(nodeId, attachment);
+ }
+
+ getNode(nodeId: string): Observable {
+ return from(this.apiService.getInstance().core.nodesApi.getNode(nodeId));
+ }
+
+ getDownload(downloadId: string): Observable {
+ return from(this.apiService.getInstance().core.downloadsApi.getDownload(downloadId));
+ }
+
+ cancelDownload(downloadId: string) {
+ this.apiService.getInstance().core.downloadsApi.cancelDownload(downloadId);
+ }
+
+ private handleError(error: any) {
+ this.logService.error(error);
+ return throwError(error || 'Server error');
+ }
+}
diff --git a/lib/core/services/public-api.ts b/lib/core/services/public-api.ts
index 78059ea9c2..84d25929d5 100644
--- a/lib/core/services/public-api.ts
+++ b/lib/core/services/public-api.ts
@@ -51,3 +51,4 @@ export * from './comment-content.service';
export * from './login-dialog.service';
export * from './external-alfresco-api.service';
export * from './jwt-helper.service';
+export * from './download-zip.service';
diff --git a/lib/core/viewer/components/viewer.component.html b/lib/core/viewer/components/viewer.component.html
index cb3c350204..592b196cd6 100644
--- a/lib/core/viewer/components/viewer.component.html
+++ b/lib/core/viewer/components/viewer.component.html
@@ -76,7 +76,7 @@
mat-icon-button
title="{{ 'ADF_VIEWER.ACTIONS.DOWNLOAD' | translate }}"
data-automation-id="adf-toolbar-download"
- (click)="downloadContent()">
+ [adfNodeDownload]="node">
file_download
diff --git a/lib/core/viewer/components/viewer.component.spec.ts b/lib/core/viewer/components/viewer.component.spec.ts
index 62aaec49a4..10d31bd09b 100644
--- a/lib/core/viewer/components/viewer.component.spec.ts
+++ b/lib/core/viewer/components/viewer.component.spec.ts
@@ -345,7 +345,10 @@ describe('ViewerComponent', () => {
const nodeDetails = { name: displayName, id: '12' };
const contentUrl = '/content/url/path';
const alfrescoApiInstanceMock = {
- nodes: { getNodeInfo: () => Promise.resolve(nodeDetails) },
+ nodes: {
+ getNodeInfo: () => Promise.resolve(nodeDetails),
+ getNode: () => Promise.resolve({ id: 'fake-node' })
+ },
content: { getContentUrl: () => contentUrl }
};
@@ -370,6 +373,8 @@ describe('ViewerComponent', () => {
Promise.resolve({ name: 'file2', content: {} })
);
+ spyOn(alfrescoApiService.nodesApi, 'getNode').and.returnValue(Promise.resolve({ id: 'fake-node' }));
+
component.urlFile = null;
component.displayName = null;
component.blobFile = null;
@@ -549,35 +554,6 @@ describe('ViewerComponent', () => {
});
});
- it('should invoke download action with the toolbar button', (done) => {
- component.allowDownload = true;
- spyOn(component, 'downloadContent').and.stub();
- fixture.detectChanges();
-
- const button: HTMLButtonElement = element.querySelector('[data-automation-id="adf-toolbar-download"]') as HTMLButtonElement;
- button.click();
-
- fixture.whenStable().then(() => {
- expect(component.downloadContent).toHaveBeenCalled();
- done();
- });
- });
-
- it('should raise download event with the toolbar button', (done) => {
- component.allowDownload = true;
- component.downloadUrl = 'URL';
- component.fileName = 'fileName';
- fixture.detectChanges();
-
- component.download.subscribe((e) => {
- expect(e).not.toBeNull();
- done();
- });
-
- const button: HTMLButtonElement = element.querySelector('[data-automation-id="adf-toolbar-download"]') as HTMLButtonElement;
- button.click();
- });
-
it('should render default print button', (done) => {
component.allowPrint = true;
fixture.detectChanges();
@@ -674,6 +650,30 @@ describe('ViewerComponent', () => {
button.click();
});
+ it('should get and assign node for download', (done) => {
+ const node = { id: 'fake-node' };
+ component.fileNodeId = '12';
+ component.urlFile = '';
+ const displayName = 'the-name';
+ const nodeDetails = { name: displayName, id: '12', content: { mimeType: 'txt' } };
+ const contentUrl = '/content/url/path';
+ const alfrescoApiInstanceMock = {
+ nodes: {
+ getNodeInfo: () => Promise.resolve(nodeDetails),
+ getNode: () => Promise.resolve(node)
+ },
+ content: { getContentUrl: () => contentUrl }
+ };
+ spyOn(alfrescoApiService, 'getInstance').and.returnValue(alfrescoApiInstanceMock);
+
+ component.ngOnChanges(null);
+ fixture.whenStable().then(() => {
+ fixture.detectChanges();
+ expect(component.node).toBe(node);
+ done();
+ });
+ });
+
});
describe('View', () => {
@@ -923,7 +923,10 @@ describe('ViewerComponent', () => {
const nodeDetails = { name: displayName, id: '12', content: { mimeType: 'txt' } };
const contentUrl = '/content/url/path';
const alfrescoApiInstanceMock = {
- nodes: { getNodeInfo: () => Promise.resolve(nodeDetails) },
+ nodes: {
+ getNodeInfo: () => Promise.resolve(nodeDetails),
+ getNode: () => Promise.resolve({ id: 'fake-node' })
+ },
content: { getContentUrl: () => contentUrl }
};
@@ -998,7 +1001,6 @@ describe('ViewerComponent', () => {
component.enterFullScreen();
expect(domElement.msRequestFullscreen).toHaveBeenCalled();
});
-
});
});
diff --git a/lib/core/viewer/components/viewer.component.ts b/lib/core/viewer/components/viewer.component.ts
index 087f28dc7b..a66366495b 100644
--- a/lib/core/viewer/components/viewer.component.ts
+++ b/lib/core/viewer/components/viewer.component.ts
@@ -21,7 +21,7 @@ import {
Input, OnChanges, Output, SimpleChanges, TemplateRef,
ViewEncapsulation, OnInit, OnDestroy
} from '@angular/core';
-import { MinimalNodeEntryEntity, RenditionEntry } from 'alfresco-js-api';
+import { MinimalNodeEntryEntity, RenditionEntry, MinimalNodeEntity } from 'alfresco-js-api';
import { BaseEvent } from '../../events';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { LogService } from '../../services/log.service';
@@ -196,10 +196,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
@Input()
fileName: string;
- /** URL to download. */
- @Input()
- downloadUrl: string = null;
-
/** Number of times the Viewer will retry fetching content Rendition.
* There is a delay of at least one second between attempts.
*/
@@ -210,10 +206,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
@Output()
goBack = new EventEmitter>();
- /** Emitted when user clicks the 'Download' button. */
- @Output()
- download = new EventEmitter>();
-
/** Emitted when user clicks the 'Print' button. */
@Output()
print = new EventEmitter>();
@@ -244,7 +236,7 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
viewerType = 'unknown';
isLoading = false;
- node: MinimalNodeEntryEntity;
+ node: MinimalNodeEntity;
extensionTemplates: { template: TemplateRef, isVisible: boolean }[] = [];
externalExtensions: string[] = [];
@@ -332,6 +324,12 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
this.logService.error('This node does not exist');
}
);
+
+ this.apiService.nodesApi.getNode(this.nodeId).then(
+ (node) => {
+ this.node = node;
+ }
+ );
} else if (this.sharedLinkId) {
this.apiService.sharedLinksApi.getSharedLink(this.sharedLinkId).then(
@@ -366,7 +364,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
this.extension = this.getFileExtension(filenameFromUrl);
this.urlFileContent = this.urlFile;
- this.downloadUrl = this.urlFile;
this.fileName = this.displayName;
this.viewerType = this.urlFileViewer || this.getViewerTypeByExtension(this.extension);
@@ -393,7 +390,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
this.extension = this.getFileExtension(data.name);
this.fileName = data.name;
- this.downloadUrl = this.apiService.contentApi.getContentUrl(data.id, true);
this.viewerType = this.getViewerTypeByExtension(this.extension);
if (this.viewerType === 'unknown') {
@@ -419,7 +415,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
this.fileName = details.entry.name;
this.urlFileContent = this.apiService.contentApi.getSharedLinkContentUrl(this.sharedLinkId, false);
- this.downloadUrl = this.apiService.contentApi.getSharedLinkContentUrl(this.sharedLinkId, true);
this.viewerType = this.getViewerTypeByMimeType(this.mimeType);
if (this.viewerType === 'unknown') {
@@ -608,25 +603,6 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
}
}
- downloadContent() {
- if (this.allowDownload && this.downloadUrl && this.fileName) {
- const args = new BaseEvent();
- this.download.next(args);
-
- if (!args.defaultPrevented) {
- const link = document.createElement('a');
-
- link.style.display = 'none';
- link.download = this.fileName;
- link.href = this.downloadUrl;
-
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- }
- }
- }
-
printContent() {
if (this.allowPrint) {
const args = new BaseEvent();
@@ -767,5 +743,4 @@ export class ViewerComponent implements OnChanges, OnInit, OnDestroy {
private generateCacheBusterNumber() {
this.cacheBusterNumber = Date.now();
}
-
}
diff --git a/lib/core/viewer/viewer.module.ts b/lib/core/viewer/viewer.module.ts
index fa877f18d4..a8ccd70fd9 100644
--- a/lib/core/viewer/viewer.module.ts
+++ b/lib/core/viewer/viewer.module.ts
@@ -39,6 +39,7 @@ import { ViewerToolbarComponent } from './components/viewer-toolbar.component';
import { ViewerComponent } from './components/viewer.component';
import { ViewerExtensionDirective } from './directives/viewer-extension.directive';
import { ViewerToolbarActionsComponent } from './components/viewer-toolbar-actions.component';
+import { DirectiveModule } from '../directives/directive.module';
@NgModule({
imports: [
@@ -49,7 +50,8 @@ import { ViewerToolbarActionsComponent } from './components/viewer-toolbar-actio
ReactiveFormsModule,
ToolbarModule,
PipeModule,
- FlexLayoutModule
+ FlexLayoutModule,
+ DirectiveModule
],
declarations: [
PdfPasswordDialogComponent,