[MNT-25896] Introduce page rotation button in pdf viewer (#12241)

* [MNT-25896] Introduce page rotation button in pdf viewer

* [MNT-25896] CR fixes
This commit is contained in:
Michal Kinas
2026-09-16 11:16:57 +02:00
committed by GitHub
parent 762eba8490
commit 1a7a59cea7
3 changed files with 53 additions and 2 deletions
@@ -106,6 +106,14 @@
<mat-icon adf-icon="zoom_out" /> <mat-icon adf-icon="zoom_out" />
</button> </button>
<button id="viewer-rotate-page-button"
title="{{ 'ADF_VIEWER.ARIA.ROTATE' | translate }}"
attr.aria-label="{{ 'ADF_VIEWER.ARIA.ROTATE' | translate }}"
mat-icon-button
(click)="rotatePage()">
<mat-icon adf-icon="rotate_left" />
</button>
<button id="viewer-scale-page-button" <button id="viewer-scale-page-button"
role="button" aria-pressed="true" role="button" aria-pressed="true"
title="{{ 'ADF_VIEWER.ARIA.FIT_PAGE' | translate }}" title="{{ 'ADF_VIEWER.ARIA.FIT_PAGE' | translate }}"
@@ -114,6 +122,5 @@
(click)="pageFit()"> (click)="pageFit()">
<mat-icon adf-icon="zoom_out_map" /> <mat-icon adf-icon="zoom_out_map" />
</button> </button>
</adf-toolbar> </adf-toolbar>
</div> </div>
@@ -461,8 +461,10 @@ describe('Test PdfViewer - User interaction', () => {
let component: PdfViewerComponent; let component: PdfViewerComponent;
let testingUtils: UnitTestingUtils; let testingUtils: UnitTestingUtils;
let pdfViewerSpy: jasmine.Spy; let pdfViewerSpy: jasmine.Spy;
let pageViewMock: { width: number; height: number; scale: number; rotation: number; update: jasmine.Spy };
beforeEach(fakeAsync(() => { beforeEach(fakeAsync(() => {
pageViewMock = { width: 100, height: 100, scale: 1, rotation: 0, update: jasmine.createSpy() };
pdfViewerSpy = jasmine.createSpy('PDFViewer').and.returnValue({ pdfViewerSpy = jasmine.createSpy('PDFViewer').and.returnValue({
setDocument: jasmine.createSpy().and.returnValue({ setDocument: jasmine.createSpy().and.returnValue({
loadingTask: () => ({ loadingTask: () => ({
@@ -479,7 +481,7 @@ describe('Test PdfViewer - User interaction', () => {
update: jasmine.createSpy(), update: jasmine.createSpy(),
currentScaleValue: 1, currentScaleValue: 1,
_currentPageNumber: 1, _currentPageNumber: 1,
_pages: [{ width: 100, height: 100, scale: 1 }] _pages: [pageViewMock]
}); });
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -617,6 +619,30 @@ describe('Test PdfViewer - User interaction', () => {
}), 300); }), 300);
}); });
describe('Rotation', () => {
it('should rotate only the current page counter-clockwise by 90 degrees', () => {
testingUtils.clickByCSS('#viewer-rotate-page-button');
expect(pageViewMock.update).toHaveBeenCalledWith({ rotation: 270 });
});
it('should wrap rotation back to 0 after a full turn', () => {
pageViewMock.rotation = 90;
testingUtils.clickByCSS('#viewer-rotate-page-button');
expect(pageViewMock.update).toHaveBeenCalledWith({ rotation: 0 });
});
it('should recompute the document overflow after rotation', () => {
spyOn(component, 'setDocumentOverflow');
testingUtils.clickByCSS('#viewer-rotate-page-button');
expect(component.setDocumentOverflow).toHaveBeenCalled();
});
});
describe('Resize interaction', () => { describe('Resize interaction', () => {
it('should resize event trigger setScaleUpdatePages', () => { it('should resize event trigger setScaleUpdatePages', () => {
spyOn(component, 'onResize'); spyOn(component, 'onResize');
@@ -577,6 +577,24 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
this.setScaleUpdatePages(newScale); this.setScaleUpdatePages(newScale);
} }
/**
* Rotate the currently displayed page 90 degrees counter-clockwise.
*
* Only the current page is affected; every other page keeps its own rotation.
* The angle wraps around, so four consecutive calls return the page to its
* original orientation (0 → 270 → 180 → 90 → 0). The document overflow state
* is recomputed afterwards, since rotation swaps the page width and height.
*/
rotatePage() {
if (this.pdfViewer) {
const pageView = this.pdfViewer._pages[this.pdfViewer._currentPageNumber - 1];
if (pageView) {
pageView.update({ rotation: (pageView.rotation + 270) % 360 });
this.setDocumentOverflow();
}
}
}
/** /**
* load the previous page * load the previous page
*/ */