mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ACA-4676][ACA-4678] Added Non Responsive Preview Dialog to viewer component (#8428)
* [ACA-4676] Added NonResponsivePreview dialog to download file incase file preview takes longer than a set period of time. * [ACA-4676] Updated button positioning for non responsive preview dialog * [ACA-4676] Added documentation for NonResponsivePreviewDialog functionality for viewer.component.ts * [ACA-4676] Added unit tests for NonResponsivePreviewDialog * [ACA-4676] Updated template of NonResponsivePreviewDialog to use components and directives from mat-dialog. Removed non-responsive-dialog.component.scss. Removed unused methods from non-responsive-dialog.component.ts * [ACA-4676] Corrected typo in NonResponsivePreviewDialog unit tests * [ACA-4676] Added test cases for NonResponsivePreviewDialog in viewer.component.ts. NOT WORKING * [ACA-4676] Fixed test cases for non-responsive preview dialog. Moved NonResponsivePreview dialog tests to separate describe block. Updated component code to make properties and methods visible to testing environment * [ACA-4676] Migrated viewer component test env setup from setupTestBed() to TestBed.configureTestingModule(). Moved NonResponsivePreviewDialog unit tests to inside parent Viewer component describe block * [ACA-4676] Removed unused async tag. Added license info to non-responsive-dialog.component.ts and non-responsive-preview-actions.enum.ts * [ACA-4676] Updated code to use "viewer" appConfig object instead of "preview-config". Added non-responsive-preview-actions.enum.ts to public-api.ts * [ACA-4676] Resolved potential lint issues * [ACA-4676] Updated non responsive preview to look for viewer config object inside app.config instead of preview-config * [ACA-4676] Removed duplicate import for @adf/core. Added NonResponsiveDialogComponent to adf/core exports * [ACA-4676] Renamed properties/config/documentation from nonResponsivePreview to downloadPrompt. Renamed NonResponsivePreviewActionsEnum to DownloadPromptActions. * [ACA-4676] Resolved linting and unit test failures * [ACA-4676] Changed dataType for timers to number. Updated code to use window.setTimeout(), instead of just setTimeout(). Added missing whitespace. Updated method names in demo shell to use 'downloadPrompt' naming scheme. * [ACA-4676] Fixed incorrect import statement in viewer.module.ts for download-prompt-dialog * [ACA-4676] Testing disabled by default behaviour of downloadPrompt feature * [ACA-4676] Changed default value for enableDownloadPrompt and enableDownloadPromptReminders to false in app.config.json * [ACA-4676] Removed un-needed AppConfig configurations from unit tests
This commit is contained in:
@@ -1478,6 +1478,10 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"viewer": {
|
"viewer": {
|
||||||
|
"enableDownloadPrompt": false,
|
||||||
|
"enableDownloadPromptReminder": false,
|
||||||
|
"downloadPromptDelay": 50,
|
||||||
|
"downloadPromptReminderDelay": 30,
|
||||||
"enableFileAutoDownload": true,
|
"enableFileAutoDownload": true,
|
||||||
"fileAutoDownloadSizeThresholdInMB": 15
|
"fileAutoDownloadSizeThresholdInMB": 15
|
||||||
}
|
}
|
||||||
|
@@ -653,6 +653,30 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<mat-slide-toggle
|
||||||
|
color="primary" [(ngModel)]="enableDownloadPrompt" id="enableDownloadPrompt" (change)="onEnableDownloadPrompt()">
|
||||||
|
Enable Download Prompt
|
||||||
|
</mat-slide-toggle>
|
||||||
|
</section>
|
||||||
|
<section *ngIf="enableDownloadPrompt">
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput type="number" [(ngModel)]="downloadPromptDelay" (change)="onDownloadPromptDelayChange()">
|
||||||
|
</mat-form-field>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section *ngIf="enableDownloadPrompt">
|
||||||
|
<mat-slide-toggle
|
||||||
|
color="primary" [(ngModel)]="enableDownloadPromptReminder" id="enableDownloadPromptReminders" (change)="onEnableDownloadPromptReminderChange()">
|
||||||
|
Enable Download Prompt Reminders
|
||||||
|
</mat-slide-toggle>
|
||||||
|
</section>
|
||||||
|
<section *ngIf="enableDownloadPrompt && enableDownloadPromptReminder">
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput type="number" [(ngModel)]="downloadPromptReminderDelay" (change)="onDownloadPromptReminderChange()">
|
||||||
|
</mat-form-field>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<mat-slide-toggle
|
<mat-slide-toggle
|
||||||
color="primary" [(ngModel)]="enableFileAutoDownload" id="enableFileAutoDownload" (change)="onEnableFileAutoDownloadChange()">
|
color="primary" [(ngModel)]="enableFileAutoDownload" id="enableFileAutoDownload" (change)="onEnableFileAutoDownloadChange()">
|
||||||
|
@@ -251,6 +251,10 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
selectedNodes = [];
|
selectedNodes = [];
|
||||||
|
|
||||||
|
enableDownloadPrompt: boolean = this.appConfig.get('viewer.enableDownloadPrompt', false);
|
||||||
|
enableDownloadPromptReminder: boolean = this.appConfig.get('viewer.enableDownloadPromptReminders', false);
|
||||||
|
downloadPromptDelay = this.appConfig.get('viewer.downloadPromptDelay', 50);
|
||||||
|
downloadPromptReminderDelay = this.appConfig.get('viewer.downloadPromptReminderDelay', 30);
|
||||||
enableFileAutoDownload: boolean = this.appConfig.get('viewer.enableFileAutoDownload', true);
|
enableFileAutoDownload: boolean = this.appConfig.get('viewer.enableFileAutoDownload', true);
|
||||||
fileAutoDownloadSizeThresholdInMB: number = this.appConfig.get('viewer.fileAutoDownloadSizeThresholdInMB', 15);
|
fileAutoDownloadSizeThresholdInMB: number = this.appConfig.get('viewer.fileAutoDownloadSizeThresholdInMB', 15);
|
||||||
|
|
||||||
@@ -780,6 +784,26 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
this.selectedNodes = [];
|
this.selectedNodes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEnableDownloadPrompt() {
|
||||||
|
const previewConfig = this.appConfig?.config['viewer'];
|
||||||
|
previewConfig['enableDownloadPrompt'] = this.enableDownloadPrompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDownloadPromptDelayChange() {
|
||||||
|
const previewConfig = this.appConfig?.config['viewer'];
|
||||||
|
previewConfig['downloadPromptDelay'] = this.downloadPromptDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnableDownloadPromptReminderChange() {
|
||||||
|
const previewConfig = this.appConfig?.config['viewer'];
|
||||||
|
previewConfig['enableDownloadPromptReminder'] = this.enableDownloadPromptReminder;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDownloadPromptReminderChange() {
|
||||||
|
const previewConfig = this.appConfig?.config['viewer'];
|
||||||
|
previewConfig['downloadPromptReminderDelay'] = this.downloadPromptReminderDelay;
|
||||||
|
}
|
||||||
|
|
||||||
onEnableFileAutoDownloadChange() {
|
onEnableFileAutoDownloadChange() {
|
||||||
const previewConfig = this.appConfig?.config['viewer'];
|
const previewConfig = this.appConfig?.config['viewer'];
|
||||||
previewConfig['enableFileAutoDownload'] = this.enableFileAutoDownload;
|
previewConfig['enableFileAutoDownload'] = this.enableFileAutoDownload;
|
||||||
|
@@ -380,6 +380,31 @@ In the same way you can set a default zoom scaling value for the image viewer by
|
|||||||
|
|
||||||
By default the viewer's zoom scaling is set to 100%.
|
By default the viewer's zoom scaling is set to 100%.
|
||||||
|
|
||||||
|
## Handling non responsive file preview
|
||||||
|
|
||||||
|
It is possible that trying to load a large file, especially over a slow network, can cause the viewer component to get stuck in the loading state. To handle such cases,
|
||||||
|
the viewer can be configured to display a prompt to ask the user to either download the file locally and then close the viewer, or wait for the viewer to load the file.
|
||||||
|
In case the user decides to wait, the viewer can further be configured to display subsequent reminder prompts asking the same options.
|
||||||
|
|
||||||
|
In order to configure this feature, add the following code in `app.config.json`.
|
||||||
|
|
||||||
|
```
|
||||||
|
"viewer": {
|
||||||
|
"enableDownloadPrompt": true,
|
||||||
|
"enableDownloadPromptReminder": true,
|
||||||
|
"downloadPromptDelay": 50,
|
||||||
|
"downloadPromptReminderDelay": 30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here `enableDownloadPrompt: true` enables the dialog to be visible after a set period of time. This time can be configured by updating the value in the
|
||||||
|
`downloadPromptDelay` property.
|
||||||
|
|
||||||
|
The second boolean flag `enableDownloadPromptReminder: true` can be used to configure whether the reminder prompts should be displayed or not.
|
||||||
|
`downloadPromptReminderDelay` property can be used to configure the time to wait between reminder prompts.
|
||||||
|
|
||||||
|
Note: All times in this configuration must be provided in seconds
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [Document List component](../../content-services/components/document-list.component.md)
|
- [Document List component](../../content-services/components/document-list.component.md)
|
||||||
|
@@ -391,7 +391,8 @@
|
|||||||
"FULLSCREEN": "Activate full-screen mode",
|
"FULLSCREEN": "Activate full-screen mode",
|
||||||
"CLOSE": "Close",
|
"CLOSE": "Close",
|
||||||
"NEXT_FILE": "Next File",
|
"NEXT_FILE": "Next File",
|
||||||
"PREV_FILE": "Previous File"
|
"PREV_FILE": "Previous File",
|
||||||
|
"WAIT": "Wait"
|
||||||
},
|
},
|
||||||
"ARIA": {
|
"ARIA": {
|
||||||
"PREVIOUS_PAGE": "Previous page",
|
"PREVIOUS_PAGE": "Previous page",
|
||||||
@@ -429,7 +430,11 @@
|
|||||||
"PLACEHOLDER": "Password",
|
"PLACEHOLDER": "Password",
|
||||||
"ERROR": "Password is wrong"
|
"ERROR": "Password is wrong"
|
||||||
},
|
},
|
||||||
"SUBTITLES": "Subtitles"
|
"SUBTITLES": "Subtitles",
|
||||||
|
"NON_RESPONSIVE_DIALOG": {
|
||||||
|
"HEADER": "Preview loading delayed",
|
||||||
|
"LABEL": "You can continue to wait, or download the document."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ERROR_CONTENT": {
|
"ERROR_CONTENT": {
|
||||||
"UNKNOWN": {
|
"UNKNOWN": {
|
||||||
|
@@ -0,0 +1,23 @@
|
|||||||
|
<div mat-dialog-title>
|
||||||
|
<h3>{{ 'ADF_VIEWER.NON_RESPONSIVE_DIALOG.HEADER' | translate }}</h3>
|
||||||
|
</div>
|
||||||
|
<mat-dialog-content>
|
||||||
|
{{ 'ADF_VIEWER.NON_RESPONSIVE_DIALOG.LABEL' | translate }}
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions align="end">
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
id="downloadButton"
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.DOWNLOAD' | translate"
|
||||||
|
[mat-dialog-close]="DownloadPromptActions.DOWNLOAD">
|
||||||
|
{{ 'ADF_VIEWER.ACTIONS.DOWNLOAD' | translate }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
id="waitButton"
|
||||||
|
color="primary"
|
||||||
|
[attr.aria-label]="'ADF_VIEWER.ACTIONS.WAIT' | translate"
|
||||||
|
[mat-dialog-close]="DownloadPromptActions.WAIT">
|
||||||
|
{{ 'ADF_VIEWER.ACTIONS.WAIT' | translate }}
|
||||||
|
</button>
|
||||||
|
</mat-dialog-actions>
|
@@ -0,0 +1,73 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CoreTestingModule, DownloadPromptDialogComponent, DownloadPromptActions } from '@alfresco/adf-core';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
const mockDialog = {
|
||||||
|
close: jasmine.createSpy('close')
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('DownloadPromptDialogComponent', () => {
|
||||||
|
let matDialogRef: MatDialogRef<DownloadPromptDialogComponent>;
|
||||||
|
let fixture: ComponentFixture<DownloadPromptDialogComponent>;
|
||||||
|
|
||||||
|
const getButton = (buttonId: string) => {
|
||||||
|
return fixture.debugElement.query(By.css(buttonId)).nativeElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [DownloadPromptDialogComponent],
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
CoreTestingModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: MatDialogRef, useValue: mockDialog }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
matDialogRef = TestBed.inject(MatDialogRef);
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DownloadPromptDialogComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit DownloadPromptActions.WAIT and close dialog when clicking on the wait button', async () => {
|
||||||
|
const waitButton = getButton('#waitButton');
|
||||||
|
waitButton.dispatchEvent(new Event('click'));
|
||||||
|
|
||||||
|
await fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(matDialogRef.close).toHaveBeenCalledWith(DownloadPromptActions.WAIT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit DownloadPromptActions.DOWNLOAD and close dialog when clicking on the download button', async () => {
|
||||||
|
const waitButton = getButton('#downloadButton');
|
||||||
|
waitButton.dispatchEvent(new Event('click'));
|
||||||
|
|
||||||
|
await fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(matDialogRef.close).toHaveBeenCalledWith(DownloadPromptActions.DOWNLOAD);
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,27 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { Component } from '@angular/core';
|
||||||
|
import { DownloadPromptActions } from '../../models/download-prompt.actions';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-download-prompt-dialog',
|
||||||
|
templateUrl: './download-prompt-dialog.component.html'
|
||||||
|
})
|
||||||
|
export class DownloadPromptDialogComponent {
|
||||||
|
DownloadPromptActions = DownloadPromptActions;
|
||||||
|
}
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
|
||||||
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
@@ -24,12 +24,15 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import {
|
import {
|
||||||
CoreTestingModule,
|
CoreTestingModule,
|
||||||
setupTestBed,
|
|
||||||
EventMock,
|
EventMock,
|
||||||
ViewerComponent,
|
ViewerComponent,
|
||||||
ViewUtilService
|
ViewUtilService,
|
||||||
|
AppConfigService,
|
||||||
|
DownloadPromptDialogComponent,
|
||||||
|
DownloadPromptActions
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-viewer-container-toolbar',
|
selector: 'adf-viewer-container-toolbar',
|
||||||
@@ -135,35 +138,48 @@ describe('ViewerComponent', () => {
|
|||||||
let element: HTMLElement;
|
let element: HTMLElement;
|
||||||
let dialog: MatDialog;
|
let dialog: MatDialog;
|
||||||
let viewUtilService: ViewUtilService;
|
let viewUtilService: ViewUtilService;
|
||||||
|
let appConfigService: AppConfigService;
|
||||||
setupTestBed({
|
|
||||||
imports: [
|
|
||||||
NoopAnimationsModule,
|
|
||||||
TranslateModule.forRoot(),
|
|
||||||
CoreTestingModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatIconModule
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
ViewerWithCustomToolbarComponent,
|
|
||||||
ViewerWithCustomSidebarComponent,
|
|
||||||
ViewerWithCustomOpenWithComponent,
|
|
||||||
ViewerWithCustomMoreActionsComponent,
|
|
||||||
ViewerWithCustomToolbarActionsComponent
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
MatDialog
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
NoopAnimationsModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
CoreTestingModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
ViewerWithCustomToolbarComponent,
|
||||||
|
ViewerWithCustomSidebarComponent,
|
||||||
|
ViewerWithCustomOpenWithComponent,
|
||||||
|
ViewerWithCustomMoreActionsComponent,
|
||||||
|
ViewerWithCustomToolbarActionsComponent
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
MatDialog,
|
||||||
|
{ provide: DownloadPromptDialogComponent, useClass: DummyDialogComponent}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ViewerComponent);
|
fixture = TestBed.createComponent(ViewerComponent);
|
||||||
element = fixture.nativeElement;
|
element = fixture.nativeElement;
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
dialog = TestBed.inject(MatDialog);
|
dialog = TestBed.inject(MatDialog);
|
||||||
viewUtilService = TestBed.inject(ViewUtilService);
|
viewUtilService = TestBed.inject(ViewUtilService);
|
||||||
|
appConfigService = TestBed.inject(AppConfigService);
|
||||||
component.fileName = 'test-file.pdf';
|
component.fileName = 'test-file.pdf';
|
||||||
|
|
||||||
|
appConfigService.config = {
|
||||||
|
...appConfigService.config,
|
||||||
|
'viewer': {
|
||||||
|
'enableDownloadPrompt': false,
|
||||||
|
'enableDownloadPromptReminder': false,
|
||||||
|
'downloadPromptDelay': 3,
|
||||||
|
'downloadPromptReminderDelay': 2
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -604,4 +620,60 @@ describe('ViewerComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Download Prompt Dialog',() => {
|
||||||
|
|
||||||
|
let dialogOpenSpy: jasmine.Spy;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
appConfigService.config = {
|
||||||
|
...appConfigService.config,
|
||||||
|
'viewer': {
|
||||||
|
'enableDownloadPrompt': true,
|
||||||
|
'enableDownloadPromptReminder': true,
|
||||||
|
'downloadPromptDelay': 3,
|
||||||
|
'downloadPromptReminderDelay': 2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dialogOpenSpy = spyOn(dialog, 'open').and.returnValue({afterClosed: () => of(null)} as any);
|
||||||
|
component.urlFile = undefined;
|
||||||
|
component.clearDownloadPromptTimeouts();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should configure initial timeout to display non responsive dialog when initialising component', (() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(component.downloadPromptTimer).toBeDefined();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should configure reminder timeout to display non responsive dialog after initial dialog', fakeAsync( () => {
|
||||||
|
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.WAIT) } as any);
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick(3000);
|
||||||
|
expect(component.downloadPromptReminderTimer).toBeDefined();
|
||||||
|
dialogOpenSpy.and.returnValue({ afterClosed: () => of(null) } as any);
|
||||||
|
flush();
|
||||||
|
discardPeriodicTasks();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show initial non responsive dialog after initial timeout', fakeAsync( () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick(3000);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(dialogOpenSpy).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should show reminder non responsive dialog after initial dialog', fakeAsync( () => {
|
||||||
|
dialogOpenSpy.and.returnValue({ afterClosed: () => of(DownloadPromptActions.WAIT) } as any);
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick(3000);
|
||||||
|
expect(dialogOpenSpy).toHaveBeenCalled();
|
||||||
|
|
||||||
|
dialogOpenSpy.and.returnValue({ afterClosed: () => of(null) } as any);
|
||||||
|
tick(2000);
|
||||||
|
expect(dialogOpenSpy).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
flush();
|
||||||
|
discardPeriodicTasks();
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -30,15 +30,25 @@ import {
|
|||||||
TemplateRef,
|
TemplateRef,
|
||||||
ViewEncapsulation
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { fromEvent, Subject } from 'rxjs';
|
import { fromEvent, Subject } from 'rxjs';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { ViewerToolbarComponent } from './viewer-toolbar.component';
|
import { ViewerToolbarComponent } from './viewer-toolbar.component';
|
||||||
import { ViewerOpenWithComponent } from './viewer-open-with.component';
|
import { ViewerOpenWithComponent } from './viewer-open-with.component';
|
||||||
import { ViewerMoreActionsComponent } from './viewer-more-actions.component';
|
import { ViewerMoreActionsComponent } from './viewer-more-actions.component';
|
||||||
import { ViewerSidebarComponent } from './viewer-sidebar.component';
|
import { ViewerSidebarComponent } from './viewer-sidebar.component';
|
||||||
import { filter, skipWhile, takeUntil } from 'rxjs/operators';
|
import { filter, first, skipWhile, takeUntil } from 'rxjs/operators';
|
||||||
import { Track } from '../models/viewer.model';
|
import { Track } from '../models/viewer.model';
|
||||||
import { ViewUtilService } from '../services/view-util.service';
|
import { ViewUtilService } from '../services/view-util.service';
|
||||||
|
import { DownloadPromptDialogComponent } from './download-prompt-dialog/download-prompt-dialog.component';
|
||||||
|
import { AppConfigService } from '../../app-config';
|
||||||
|
import { DownloadPromptActions } from '../models/download-prompt.actions';
|
||||||
|
|
||||||
|
const DEFAULT_NON_PREVIEW_CONFIG = {
|
||||||
|
enableDownloadPrompt: false,
|
||||||
|
enableDownloadPromptReminder: false,
|
||||||
|
downloadPromptDelay: 50,
|
||||||
|
downloadPromptReminderDelay: 30
|
||||||
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-viewer',
|
selector: 'adf-viewer',
|
||||||
@@ -160,6 +170,26 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
@Input()
|
@Input()
|
||||||
sidebarLeftTemplateContext: T = null;
|
sidebarLeftTemplateContext: T = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable dialog box to allow user to download the previewed file, in case the preview is not responding for a set period of time.
|
||||||
|
* */
|
||||||
|
enableDownloadPrompt: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable reminder dialogs to prompt user to download the file, in case the preview is not responding for a set period of time.
|
||||||
|
* */
|
||||||
|
enableDownloadPromptReminder: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial time in seconds to wait before giving the first prompt to user to download the file
|
||||||
|
* */
|
||||||
|
downloadPromptDelay: number = 50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time in seconds to wait before giving the second and consequent reminders to the user to download the file.
|
||||||
|
* */
|
||||||
|
downloadPromptReminderDelay: number = 15;
|
||||||
|
|
||||||
/** Emitted when user clicks 'Navigate Before' ("<") button. */
|
/** Emitted when user clicks 'Navigate Before' ("<") button. */
|
||||||
@Output()
|
@Output()
|
||||||
navigateBefore = new EventEmitter<MouseEvent | KeyboardEvent>();
|
navigateBefore = new EventEmitter<MouseEvent | KeyboardEvent>();
|
||||||
@@ -180,10 +210,14 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
|
|
||||||
private closeViewer = true;
|
private closeViewer = true;
|
||||||
private keyDown$ = fromEvent<KeyboardEvent>(document, 'keydown');
|
private keyDown$ = fromEvent<KeyboardEvent>(document, 'keydown');
|
||||||
|
private isDialogVisible: boolean = false;
|
||||||
|
public downloadPromptTimer: number;
|
||||||
|
public downloadPromptReminderTimer: number;
|
||||||
|
|
||||||
constructor(private el: ElementRef,
|
constructor(private el: ElementRef,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
private viewUtilsService: ViewUtilService
|
private viewUtilsService: ViewUtilService,
|
||||||
|
private appConfigService: AppConfigService
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +236,7 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.closeOverlayManager();
|
this.closeOverlayManager();
|
||||||
|
this.configureAndInitDownloadPrompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
private closeOverlayManager() {
|
private closeOverlayManager() {
|
||||||
@@ -304,8 +339,64 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
this.clearDownloadPromptTimeouts();
|
||||||
this.onDestroy$.next(true);
|
this.onDestroy$.next(true);
|
||||||
this.onDestroy$.complete();
|
this.onDestroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private configureAndInitDownloadPrompt() {
|
||||||
|
this.configureDownloadPromptProperties();
|
||||||
|
if (this.enableDownloadPrompt) {
|
||||||
|
this.initDownloadPrompt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private configureDownloadPromptProperties() {
|
||||||
|
const nonResponsivePreviewConfig = this.appConfigService.get('viewer', DEFAULT_NON_PREVIEW_CONFIG);
|
||||||
|
|
||||||
|
this.enableDownloadPrompt = nonResponsivePreviewConfig.enableDownloadPrompt;
|
||||||
|
this.enableDownloadPromptReminder = nonResponsivePreviewConfig.enableDownloadPromptReminder;
|
||||||
|
this.downloadPromptDelay = nonResponsivePreviewConfig.downloadPromptDelay;
|
||||||
|
this.downloadPromptReminderDelay = nonResponsivePreviewConfig.downloadPromptReminderDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initDownloadPrompt() {
|
||||||
|
this.downloadPromptTimer = window.setTimeout(() => {
|
||||||
|
this.showOrClearDownloadPrompt();
|
||||||
|
}, this.downloadPromptDelay * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private showOrClearDownloadPrompt() {
|
||||||
|
if (!this.urlFile) {
|
||||||
|
this.showDownloadPrompt();
|
||||||
|
} else {
|
||||||
|
this.clearDownloadPromptTimeouts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearDownloadPromptTimeouts() {
|
||||||
|
if (this.downloadPromptTimer) {
|
||||||
|
clearTimeout(this.downloadPromptTimer);
|
||||||
|
}
|
||||||
|
if (this.downloadPromptReminderTimer) {
|
||||||
|
clearTimeout(this.downloadPromptReminderTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private showDownloadPrompt() {
|
||||||
|
if (!this.isDialogVisible) {
|
||||||
|
this.isDialogVisible = true;
|
||||||
|
this.dialog.open(DownloadPromptDialogComponent, { disableClose: true }).afterClosed().pipe(first()).subscribe((result: DownloadPromptActions) => {
|
||||||
|
this.isDialogVisible = false;
|
||||||
|
if (result === DownloadPromptActions.WAIT) {
|
||||||
|
if (this.enableDownloadPromptReminder) {
|
||||||
|
this.clearDownloadPromptTimeouts();
|
||||||
|
this.downloadPromptReminderTimer = window.setTimeout(() => {
|
||||||
|
this.showOrClearDownloadPrompt();
|
||||||
|
}, this.downloadPromptReminderDelay * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
22
lib/core/src/lib/viewer/models/download-prompt.actions.ts
Normal file
22
lib/core/src/lib/viewer/models/download-prompt.actions.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Enum listing the allowed actions that can be emitted from the NonResponsivePreview dialog component */
|
||||||
|
export enum DownloadPromptActions {
|
||||||
|
'WAIT',
|
||||||
|
'DOWNLOAD'
|
||||||
|
}
|
@@ -33,9 +33,11 @@ export * from './components/viewer-toolbar-actions.component';
|
|||||||
export * from './components/viewer-toolbar-custom-actions.component';
|
export * from './components/viewer-toolbar-custom-actions.component';
|
||||||
export * from './components/viewer-render.component';
|
export * from './components/viewer-render.component';
|
||||||
export * from './components/viewer.component';
|
export * from './components/viewer.component';
|
||||||
|
export * from './components/download-prompt-dialog/download-prompt-dialog.component';
|
||||||
|
|
||||||
export * from './directives/viewer-extension.directive';
|
export * from './directives/viewer-extension.directive';
|
||||||
|
|
||||||
export * from './viewer.module';
|
export * from './viewer.module';
|
||||||
|
|
||||||
export * from './models/viewer.model';
|
export * from './models/viewer.model';
|
||||||
|
export * from './models/download-prompt.actions';
|
||||||
|
@@ -45,6 +45,7 @@ import { DirectiveModule } from '../directives/directive.module';
|
|||||||
import { A11yModule } from '@angular/cdk/a11y';
|
import { A11yModule } from '@angular/cdk/a11y';
|
||||||
import { ViewerComponent } from './components/viewer.component';
|
import { ViewerComponent } from './components/viewer.component';
|
||||||
import { ViewerToolbarCustomActionsComponent } from './components/viewer-toolbar-custom-actions.component';
|
import { ViewerToolbarCustomActionsComponent } from './components/viewer-toolbar-custom-actions.component';
|
||||||
|
import { DownloadPromptDialogComponent } from './components/download-prompt-dialog/download-prompt-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -77,7 +78,8 @@ import { ViewerToolbarCustomActionsComponent } from './components/viewer-toolbar
|
|||||||
ViewerMoreActionsComponent,
|
ViewerMoreActionsComponent,
|
||||||
ViewerToolbarActionsComponent,
|
ViewerToolbarActionsComponent,
|
||||||
ViewerComponent,
|
ViewerComponent,
|
||||||
ViewerToolbarCustomActionsComponent
|
ViewerToolbarCustomActionsComponent,
|
||||||
|
DownloadPromptDialogComponent
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
ViewerRenderComponent,
|
ViewerRenderComponent,
|
||||||
|
Reference in New Issue
Block a user