diff --git a/docs/.DS_Store b/docs/.DS_Store index f87d80dfc5..648749ffc5 100644 Binary files a/docs/.DS_Store and b/docs/.DS_Store differ diff --git a/docs/core/components/viewer.component.md b/docs/core/components/viewer.component.md index 867edd47a8..a2a23ea68d 100644 --- a/docs/core/components/viewer.component.md +++ b/docs/core/components/viewer.component.md @@ -467,6 +467,23 @@ You can enable a custom "More actions" menu by providing at least one action ins ![More actions](../../docassets/images/viewer-more-actions.png) +#### Custom zoom scaling + +You can set a default zoom scaling value for pdf viewer by adding the following code in `app.config.json`. +Note: For the pdf viewer the value has to be within the range of 25 - 1000. + +"adf-viewer": { + "pdf-viewer-scaling": 150 + } + +In the same way you can set a default zoom scaling value for the image viewer by adding the following code in `app.config.json`. + +"adf-viewer": { + "image-viewer-scaling": 150 + } + +By default the viewer's zoom scaling is set to 100%. + ### Printing You can configure the Viewer to let the user print the displayed content. The diff --git a/lib/core/app-config/schema.json b/lib/core/app-config/schema.json index bf6809bf16..1cb940c240 100644 --- a/lib/core/app-config/schema.json +++ b/lib/core/app-config/schema.json @@ -1325,6 +1325,20 @@ } } } + }, + "adf-viewer": { + "description": "Viewer default properties", + "type": "object", + "properties": { + "pdf-viewer-scaling": { + "type": "number", + "minimum": 25, + "maximum": 1000 + }, + "image-viewer-scaling": { + "type": "number" + } + } } } } diff --git a/lib/core/viewer/components/imgViewer.component.spec.ts b/lib/core/viewer/components/imgViewer.component.spec.ts index d5cf5bac2d..6c22628191 100644 --- a/lib/core/viewer/components/imgViewer.component.spec.ts +++ b/lib/core/viewer/components/imgViewer.component.spec.ts @@ -22,6 +22,7 @@ import { ContentService } from '../../services/content.service'; import { ImgViewerComponent } from './imgViewer.component'; import { setupTestBed } from '../../testing/setupTestBed'; import { CoreModule } from '../../core.module'; +import { AppConfigService, AppConfigServiceMock } from '@alfresco/adf-core'; describe('Test Img viewer component ', () => { @@ -32,12 +33,15 @@ describe('Test Img viewer component ', () => { function createFakeBlob() { const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); - return new Blob([data], {type: 'image/png'}); + return new Blob([data], { type: 'image/png' }); } setupTestBed({ imports: [ CoreModule.forRoot() + ], + providers: [ + { provide: AppConfigService, useClass: AppConfigServiceMock } ] }); @@ -250,4 +254,37 @@ describe('Test Img viewer component ', () => { }).not.toThrow(new Error('Attribute urlFile or blobFile is required')); expect(component.urlFile).toEqual('fake-blob-url'); }); + + describe('Zoom customization', () => { + + describe('default value', () => { + + it('should use default zoom if is not present a custom zoom in the app.config', () => { + expect(component.scaleX).toBe(1.0); + expect(component.scaleY).toBe(1.0); + }); + + }); + + describe('custom value', () => { + + beforeEach(() => { + const appConfig: AppConfigService = TestBed.get(AppConfigService); + appConfig.config['adf-viewer.image-viewer-scaling'] = 70; + component.initializeScaling(); + }); + + it('should use the custom zoom if it is present in the app.config', (done) => { + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(component.scaleX).toBe(0.70); + expect(component.scaleY).toBe(0.70); + done(); + }); + }); + }); + + }); + }); diff --git a/lib/core/viewer/components/imgViewer.component.ts b/lib/core/viewer/components/imgViewer.component.ts index e6c176cd76..016387aba7 100644 --- a/lib/core/viewer/components/imgViewer.component.ts +++ b/lib/core/viewer/components/imgViewer.component.ts @@ -15,8 +15,18 @@ * limitations under the License. */ -import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation, ElementRef, OnInit, OnDestroy } from '@angular/core'; +import { + Component, + Input, + OnChanges, + SimpleChanges, + ViewEncapsulation, + ElementRef, + OnInit, + OnDestroy +} from '@angular/core'; import { ContentService } from '../../services/content.service'; +import { AppConfigService } from './../../app-config/app-config.service'; @Component({ selector: 'adf-img-viewer', @@ -60,8 +70,18 @@ export class ImgViewerComponent implements OnInit, OnChanges, OnDestroy { private element: HTMLElement; constructor( + private appConfigService: AppConfigService, private contentService: ContentService, private el: ElementRef) { + this.initializeScaling(); + } + + initializeScaling() { + const scaling = this.appConfigService.get('adf-viewer.image-viewer-scaling', undefined) / 100; + if (scaling) { + this.scaleX = scaling; + this.scaleY = scaling; + } } ngOnInit() { diff --git a/lib/core/viewer/components/pdfViewer.component.spec.ts b/lib/core/viewer/components/pdfViewer.component.spec.ts index bf27dac71a..073f9af22d 100644 --- a/lib/core/viewer/components/pdfViewer.component.spec.ts +++ b/lib/core/viewer/components/pdfViewer.component.spec.ts @@ -28,6 +28,7 @@ import { CoreModule } from '../../core.module'; import { TranslationService } from '../../services/translation.service'; import { TranslationMock } from '../../mock/translation.service.mock'; import { take } from 'rxjs/operators'; +import { AppConfigService, AppConfigServiceMock } from '@alfresco/adf-core'; declare const pdfjsLib: any; @@ -137,6 +138,7 @@ describe('Test PdfViewer component', () => { ], providers: [ { provide: TranslationService, useClass: TranslationMock }, + { provide: AppConfigService, useClass: AppConfigServiceMock }, { provide: MatDialog, useValue: { open: () => { @@ -634,4 +636,163 @@ describe('Test PdfViewer component', () => { }); + describe('Zoom customization', () => { + + describe('default value', () => { + + let fixtureUrlTestComponent: ComponentFixture; + let componentUrlTestComponent: UrlTestComponent; + let elementUrlTestComponent: HTMLElement; + + beforeEach((done) => { + fixtureUrlTestComponent = TestBed.createComponent(UrlTestComponent); + componentUrlTestComponent = fixtureUrlTestComponent.componentInstance; + elementUrlTestComponent = fixtureUrlTestComponent.nativeElement; + + fixtureUrlTestComponent.detectChanges(); + + componentUrlTestComponent.pdfViewerComponent.rendered + .pipe(take(1)) + .subscribe(() => { + done(); + }); + }); + + afterEach(() => { + document.body.removeChild(elementUrlTestComponent); + }); + + it('should use default zoom if is not present a custom zoom in the app.config', (done) => { + spyOn(componentUrlTestComponent.pdfViewerComponent.pdfViewer, 'forceRendering').and.callFake(() => { + }); + + fixtureUrlTestComponent.detectChanges(); + fixtureUrlTestComponent.whenStable().then(() => { + expect(componentUrlTestComponent.pdfViewerComponent.currentScale).toBe(1); + done(); + }); + }); + }); + + describe('custom value', () => { + + let fixtureUrlTestComponent: ComponentFixture; + let componentUrlTestComponent: UrlTestComponent; + let elementUrlTestComponent: HTMLElement; + + beforeEach((done) => { + const appConfig: AppConfigService = TestBed.get(AppConfigService); + appConfig.config['adf-viewer.pdf-viewer-scaling'] = 80; + + fixtureUrlTestComponent = TestBed.createComponent(UrlTestComponent); + componentUrlTestComponent = fixtureUrlTestComponent.componentInstance; + elementUrlTestComponent = fixtureUrlTestComponent.nativeElement; + + fixtureUrlTestComponent.detectChanges(); + + componentUrlTestComponent.pdfViewerComponent.rendered + .pipe(take(1)) + .subscribe(() => { + done(); + }); + }); + + afterEach(() => { + document.body.removeChild(elementUrlTestComponent); + }); + + it('should use the custom zoom if it is present in the app.config', (done) => { + spyOn(componentUrlTestComponent.pdfViewerComponent.pdfViewer, 'forceRendering').and.callFake(() => { + }); + + fixtureUrlTestComponent.detectChanges(); + fixtureUrlTestComponent.whenStable().then(() => { + expect(componentUrlTestComponent.pdfViewerComponent.currentScale).toBe(0.8); + done(); + }); + }); + }); + + describe('less than the minimum allowed value', () => { + + let fixtureUrlTestComponent: ComponentFixture; + let componentUrlTestComponent: UrlTestComponent; + let elementUrlTestComponent: HTMLElement; + + beforeEach((done) => { + const appConfig: AppConfigService = TestBed.get(AppConfigService); + appConfig.config['adf-viewer.pdf-viewer-scaling'] = 10; + + fixtureUrlTestComponent = TestBed.createComponent(UrlTestComponent); + componentUrlTestComponent = fixtureUrlTestComponent.componentInstance; + elementUrlTestComponent = fixtureUrlTestComponent.nativeElement; + + fixtureUrlTestComponent.detectChanges(); + + componentUrlTestComponent.pdfViewerComponent.rendered + .pipe(take(1)) + .subscribe(() => { + done(); + }); + }); + + afterEach(() => { + document.body.removeChild(elementUrlTestComponent); + }); + + it('should use the minimum scale zoom if the value given in app.config is less than the minimum allowed scale', (done) => { + spyOn(componentUrlTestComponent.pdfViewerComponent.pdfViewer, 'forceRendering').and.callFake(() => { + }); + + fixtureUrlTestComponent.detectChanges(); + + fixtureUrlTestComponent.whenStable().then(() => { + expect(componentUrlTestComponent.pdfViewerComponent.currentScale).toBe(0.25); + done(); + }); + }); + + }); + + describe('greater than the maximum allowed value', () => { + + let fixtureUrlTestComponent: ComponentFixture; + let componentUrlTestComponent: UrlTestComponent; + let elementUrlTestComponent: HTMLElement; + + beforeEach((done) => { + const appConfig: AppConfigService = TestBed.get(AppConfigService); + appConfig.config['adf-viewer.pdf-viewer-scaling'] = 55555; + + fixtureUrlTestComponent = TestBed.createComponent(UrlTestComponent); + componentUrlTestComponent = fixtureUrlTestComponent.componentInstance; + elementUrlTestComponent = fixtureUrlTestComponent.nativeElement; + + fixtureUrlTestComponent.detectChanges(); + + componentUrlTestComponent.pdfViewerComponent.rendered + .pipe(take(1)) + .subscribe(() => { + done(); + }); + }); + + afterEach(() => { + document.body.removeChild(elementUrlTestComponent); + }); + + it('should use the maximum scale zoom if the value given in app.config is greater than the maximum allowed scale', (done) => { + spyOn(componentUrlTestComponent.pdfViewerComponent.pdfViewer, 'forceRendering').and.callFake(() => { + }); + + fixtureUrlTestComponent.detectChanges(); + fixtureUrlTestComponent.whenStable().then(() => { + expect(componentUrlTestComponent.pdfViewerComponent.currentScale).toBe(10); + done(); + + }); + + }); + }); + }); }); diff --git a/lib/core/viewer/components/pdfViewer.component.ts b/lib/core/viewer/components/pdfViewer.component.ts index beda5faa12..e0799de6d5 100644 --- a/lib/core/viewer/components/pdfViewer.component.ts +++ b/lib/core/viewer/components/pdfViewer.component.ts @@ -114,6 +114,26 @@ export class PdfViewerComponent implements OnChanges, OnDestroy { this.onPagesLoaded = this.onPagesLoaded.bind(this); this.onPageRendered = this.onPageRendered.bind(this); this.randomPdfId = this.generateUuid(); + this.currentScale = this.getUserScaling(); + } + + getUserScaling(): number { + const scaleConfig = this.appConfigService.get('adf-viewer.pdf-viewer-scaling', undefined) / 100; + if (scaleConfig) { + return this.checkLimits(scaleConfig); + } else { + return 1; + } + } + + checkLimits(scaleConfig: number): number { + if (scaleConfig > this.MAX_SCALE) { + return this.MAX_SCALE; + } else if (scaleConfig < this.MIN_SCALE) { + return this.MIN_SCALE; + } else { + return scaleConfig; + } } ngOnChanges(changes: SimpleChanges) { @@ -235,10 +255,10 @@ export class PdfViewerComponent implements OnChanges, OnDestroy { scalePage(scaleMode) { this.currentScaleMode = scaleMode; - if (this.pdfViewer) { + const viewerContainer = document.getElementById(`${this.randomPdfId}-viewer-main-container`); + const documentContainer = document.getElementById(`${this.randomPdfId}-viewer-pdf-viewer`); - const viewerContainer = document.getElementById(`${this.randomPdfId}-viewer-main-container`); - const documentContainer = document.getElementById(`${this.randomPdfId}-viewer-pdf-viewer`); + if (this.pdfViewer && documentContainer) { let widthContainer; let heightContainer; @@ -257,37 +277,42 @@ export class PdfViewerComponent implements OnChanges, OnDestroy { const pageWidthScale = (widthContainer - padding) / currentPage.width * currentPage.scale; const pageHeightScale = (heightContainer - padding) / currentPage.width * currentPage.scale; - let scale; + let scale = this.getUserScaling(); + if (!scale) { + switch (this.currentScaleMode) { + case 'page-actual': + scale = 1; + break; + case 'page-width': + scale = pageWidthScale; + break; + case 'page-height': + scale = pageHeightScale; + break; + case 'page-fit': + scale = Math.min(pageWidthScale, pageHeightScale); + break; + case 'auto': + let horizontalScale; + if (this.isLandscape) { + horizontalScale = Math.min(pageHeightScale, pageWidthScale); + } else { + horizontalScale = pageWidthScale; + } + horizontalScale = Math.round(horizontalScale); + scale = Math.min(this.MAX_AUTO_SCALE, horizontalScale); - switch (this.currentScaleMode) { - case 'page-actual': - scale = 1; - break; - case 'page-width': - scale = pageWidthScale; - break; - case 'page-height': - scale = pageHeightScale; - break; - case 'page-fit': - scale = Math.min(pageWidthScale, pageHeightScale); - break; - case 'auto': - let horizontalScale; - if (this.isLandscape) { - horizontalScale = Math.min(pageHeightScale, pageWidthScale); - } else { - horizontalScale = pageWidthScale; - } - scale = Math.min(this.MAX_AUTO_SCALE, horizontalScale); + break; + default: + this.logService.error('pdfViewSetScale: \'' + scaleMode + '\' is an unknown zoom value.'); + return; + } - break; - default: - this.logService.error('pdfViewSetScale: \'' + scaleMode + '\' is an unknown zoom value.'); - return; + this.setScaleUpdatePages(scale); + } else { + this.currentScale = 0; + this.setScaleUpdatePages(scale); } - - this.setScaleUpdatePages(scale); } }