diff --git a/ng2-components/ng2-alfresco-viewer/src/assets/PDFViewer.mock.ts b/ng2-components/ng2-alfresco-viewer/src/assets/PDFViewer.mock.ts index 2e2838d6b2..e9bbab730a 100644 --- a/ng2-components/ng2-alfresco-viewer/src/assets/PDFViewer.mock.ts +++ b/ng2-components/ng2-alfresco-viewer/src/assets/PDFViewer.mock.ts @@ -23,4 +23,25 @@ export class PDFViewermock { currentPage = { renderingState: 3 as number }; + + _pages: any = + [{ + width: 793, + scale: 1, + update: this.update + }, { + width: 793, + scale: 1, + update: this.update + }, { + width: 793, + scale: 1, + update: this.update + }]; + + _currentPageNumber: number = 0; + + update() { + console.log('update page'); + } } diff --git a/ng2-components/ng2-alfresco-viewer/src/assets/event.mock.ts b/ng2-components/ng2-alfresco-viewer/src/assets/event.mock.ts new file mode 100644 index 0000000000..eb606201f3 --- /dev/null +++ b/ng2-components/ng2-alfresco-viewer/src/assets/event.mock.ts @@ -0,0 +1,35 @@ +/*! + * @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 class EventMock { + + static keyDown(key: any) { + let event: any = document.createEvent('Event'); + event.keyCode = key; + event.initEvent('keydown'); + document.dispatchEvent(event); + } + + static resizeMobileView() { + window.innerWidth = 320; + window.innerHeight = 568; + window.dispatchEvent(new Event('resize')); + } +} + + diff --git a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.css b/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.css index 3b15d30246..540d4cc8fa 100644 --- a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.css +++ b/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.css @@ -16,3 +16,7 @@ align-items: center; justify-content: center; } + +.full_width{ + width :100% !important; +} diff --git a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.html b/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.html index 8affda71b4..0fd7a550cd 100644 --- a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.html +++ b/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.html @@ -1,10 +1,10 @@
-
+

File {{nameFile}} is an unsupported format

-
diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.css b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.css index 4e31b8f6f4..3db514948a 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.css +++ b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.css @@ -2,21 +2,29 @@ background: #3E3E3E; } -.viewer-loader-text { +.loader-container { + display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */ + display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */ + display: -webkit-flex; /* NEW - Chrome */ + display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */ + -webkit-box-flex-direction: row; + -moz-box-flex-direction: row; + -webkit-flex-direction: row; + flex-direction: row; + height:100%; +} + +.loader-item { + margin: auto; + max-height:100px; + max-width:300px; +} + +.loader-text{ + white-space: nowrap; text-align: center; - color: #000; -} - -:host .page { - margin: 10px auto !important; - overflow: visible; - border: 9px solid transparent; - background-clip: content-box; - background-color: white; -} - -:host .canvasWrapper { - box-shadow: 0px 0px 8px 2px #000; + position: relative; + color : #fff; } .left { @@ -34,6 +42,18 @@ color: white; } +.viewer-toolbar-command{ + height: 30px; + padding-top: 4px; + top: 80px; + left:35px; + width:auto; + position:fixed; + border-radius: 10px; + background: #3E3E3E; + color: white; +} + .viewer-pagenumber-input { border: none; border-bottom: 1px solid rgba(0,0,0,.12); diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.html b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.html index 2da07b540f..91edb01582 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.html +++ b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.html @@ -1,11 +1,11 @@ -
-
-
-
-
-
-
Loading...
+
+
+
+
+
+
Loading {{nameFile}} ...
+
@@ -24,8 +24,16 @@
/ {{totalPages}}
-
+
keyboard_arrow_right
+ + +
+
+ zoom_out_map +
+
+ diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.spec.ts b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.spec.ts index d22ba9a324..a1804ead3f 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.spec.ts +++ b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.spec.ts @@ -24,6 +24,7 @@ import { import { PdfViewerComponent } from './pdfViewer.component'; import { PDFJSmock } from './assets/PDFJS.mock'; import { PDFViewermock } from './assets/PDFViewer.mock'; +import { EventMock } from './assets/event.mock'; describe('PdfViewer', () => { setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, @@ -51,11 +52,10 @@ describe('PdfViewer', () => { fixture.detectChanges(); - expect(element.querySelector('#viewer-loader')).not.toBeNull(); + expect(element.querySelector('#loader-container')).not.toBeNull(); }); })); - it('Next an Previous Buttons should be present', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { return tcb .createAsync(PdfViewerComponent) @@ -104,7 +104,8 @@ describe('PdfViewer', () => { }); })); - it('nextPage should move to the next page', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + + it('right arrow should move to the next page', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { return tcb .createAsync(PdfViewerComponent) .then((fixture) => { @@ -119,7 +120,61 @@ describe('PdfViewer', () => { component.ngOnChanges().then(() => { fixture.detectChanges(); expect(component.displayPage).toBe(1); - component.nextPage(); + EventMock.keyDown(39); + fixture.detectChanges(); + expect(component.displayPage).toBe(2); + }).catch((error) => { + expect(error).toBeUndefined(); + }); + }); + })); + + it('nextPage should move to the next page', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + return tcb + .createAsync(PdfViewerComponent) + .then((fixture) => { + let component = fixture.componentInstance; + let element = fixture.nativeElement; + + spyOn(component, 'getPDFJS').and.returnValue(new PDFJSmock()); + spyOn(component, 'initPDFViewer').and.callFake(() => { + component.pdfViewer = new PDFViewermock(); + }); + + component.urlFile = 'fake-url-file'; + + let nextPageButton = element.querySelector('#viewer-next-page-button'); + + component.ngOnChanges().then(() => { + fixture.detectChanges(); + expect(component.displayPage).toBe(1); + nextPageButton.click(); + fixture.detectChanges(); + expect(component.displayPage).toBe(2); + }).catch((error) => { + expect(error).toBeUndefined(); + }); + }); + })); + + it('left arrow should move to the previous page', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + return tcb + .createAsync(PdfViewerComponent) + .then((fixture) => { + let component = fixture.componentInstance; + spyOn(component, 'getPDFJS').and.returnValue(new PDFJSmock()); + spyOn(component, 'initPDFViewer').and.callFake(() => { + component.pdfViewer = new PDFViewermock(); + }); + + component.urlFile = 'fake-url-file'; + + component.ngOnChanges().then(() => { + fixture.detectChanges(); + expect(component.displayPage).toBe(1); + EventMock.keyDown(39); + EventMock.keyDown(39); + EventMock.keyDown(37); fixture.detectChanges(); expect(component.displayPage).toBe(2); }).catch((error) => { @@ -133,19 +188,23 @@ describe('PdfViewer', () => { .createAsync(PdfViewerComponent) .then((fixture) => { let component = fixture.componentInstance; + let element = fixture.nativeElement; + spyOn(component, 'getPDFJS').and.returnValue(new PDFJSmock()); spyOn(component, 'initPDFViewer').and.callFake(() => { component.pdfViewer = new PDFViewermock(); }); component.urlFile = 'fake-url-file'; + let previousPageButton = element.querySelector('#viewer-previous-page-button'); + let nextPageButton = element.querySelector('#viewer-next-page-button'); component.ngOnChanges().then(() => { fixture.detectChanges(); expect(component.displayPage).toBe(1); - component.nextPage(); - component.nextPage(); - component.previousPage(); + nextPageButton.click(); + nextPageButton.click(); + previousPageButton.click(); fixture.detectChanges(); expect(component.displayPage).toBe(2); }).catch((error) => { @@ -178,5 +237,56 @@ describe('PdfViewer', () => { }); }); })); + + it('Input page should move to the inserted page', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + return tcb + .createAsync(PdfViewerComponent) + .then((fixture) => { + let component = fixture.componentInstance; + + spyOn(component, 'getPDFJS').and.returnValue(new PDFJSmock()); + spyOn(component, 'initPDFViewer').and.callFake(() => { + component.pdfViewer = new PDFViewermock(); + }); + + component.urlFile = 'fake-url-file'; + + component.ngOnChanges().then(() => { + fixture.detectChanges(); + expect(component.displayPage).toBe(1); + component.inputPage('4'); + fixture.detectChanges(); + expect(component.displayPage).toBe(4); + }).catch((error) => { + expect(error).toBeUndefined(); + }); + }); + })); }); + + describe('Rezize interaction', () => { + + it('resize event should trigger setScaleUpdatePages', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + return tcb + .createAsync(PdfViewerComponent) + .then((fixture) => { + let component = fixture.componentInstance; + let element = fixture.nativeElement; + + spyOn(component, 'getPDFJS').and.returnValue(new PDFJSmock()); + spyOn(component, 'initPDFViewer'); + spyOn(component, 'setScaleUpdatePages'); + + component.documentContainer = element.querySelector('#viewer-pdf-container'); + component.pdfViewer = new PDFViewermock(); + component.urlFile = 'fake-url-file'; + + EventMock.resizeMobileView(); + + expect(component.setScaleUpdatePages).toHaveBeenCalled(); + }); + })); + + }); + }); diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.ts b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.ts index 65a4c9514d..1d66123e82 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.ts +++ b/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.ts @@ -24,13 +24,16 @@ declare let __moduleName: string; moduleId: __moduleName, selector: 'pdf-viewer', templateUrl: './pdfViewer.component.html', - styleUrls: ['./pdfViewer.component.css'] + styleUrls: ['./pdfViewer.component.css', './pdfViewerHost.component.css'] }) export class PdfViewerComponent { @Input() urlFile: string; + @Input() + nameFile: string; + currentPdfDocument: any; page: number; displayPage: number; @@ -38,9 +41,10 @@ export class PdfViewerComponent { pdfViewer: any; - renderingStates = { - FINISHED: 3 as number - }; + currentScaleMode: string = 'auto'; + currentScale: number; + + MAX_AUTO_SCALE: number = 1.25; ngOnChanges(changes) { if (!this.urlFile) { @@ -55,6 +59,11 @@ export class PdfViewerComponent { this.page = 1; this.displayPage = 1; this.initPDFViewer(this.currentPdfDocument); + + this.currentPdfDocument.getPage(1).then(() => { + this.scalePage('auto'); + }); + }, (error) => { reject(error); }); @@ -73,8 +82,9 @@ export class PdfViewerComponent { initPDFViewer(pdfDocument: any) { PDFJS.verbosity = 5; + PDFJS.disableWorker = true; - let documentContainer: any = document.getElementById('viewer-pdf-container'); + let documentContainer = document.getElementById('viewer-pdf-container'); let viewer: any = document.getElementById('viewer-viewerPdf'); this.pdfViewer = new PDFJS.PDFViewer({ @@ -85,6 +95,107 @@ export class PdfViewerComponent { this.pdfViewer.setDocument(pdfDocument); } + + /** + * Method to scale the page current support implementation + * @param {string} scaleMode - new scale mode + */ + scalePage(scaleMode) { + this.currentScaleMode = scaleMode; + + if (this.pdfViewer) { + let documentContainer = document.getElementById('viewer-pdf-container'); + let currentPage = this.pdfViewer._pages[this.pdfViewer._currentPageNumber]; + + let padding = 20; + let pageWidthScale = (documentContainer.clientWidth - padding) / currentPage.width * currentPage.scale; + let pageHeightScale = (documentContainer.clientHeight - padding) / currentPage.width * currentPage.scale; + + let 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; + } + scale = Math.min(this.MAX_AUTO_SCALE, horizontalScale); + + break; + default: + console.error('pdfViewSetScale: \'' + scaleMode + '\' is an unknown zoom value.'); + return; + } + + this.setScaleUpdatePages(scale); + } + } + + /** + * Update all the pages with the newScale scale + * @param {number} newScale - new scale page + */ + setScaleUpdatePages(newScale: number) { + if (!this.isSameScale(this.currentScale, newScale)) { + this.currentScale = newScale; + + this.pdfViewer._pages.forEach(function (currentPage) { + currentPage.update(newScale); + }); + + this.pdfViewer.update(); + } + } + + /** + * method to check if the request scale of the page is the same for avoid unuseful re-rendering + * + * @param {number} oldScale - old scale page + * @param {number} newScale - new scale page + */ + isSameScale(oldScale: number, newScale: number) { + return (newScale === oldScale); + } + + + /** + * method to check if is a land scape view + * + * @param {number} width + * @param {number} height + */ + isLandscape(width: number, height: number) { + return (width > height); + } + + /** + * Method triggered when the page is resized + */ + onResize() { + this.scalePage(this.currentScaleMode); + } + + /** + * Method triggered when the page is resized + */ + pageFit() { + this.scalePage('page-fit'); + } + /** * load the previous page */ @@ -94,12 +205,6 @@ export class PdfViewerComponent { this.displayPage = this.page; this.pdfViewer.currentPageNumber = this.page; - - //if (this.pdfViewer.currentPage.renderingState === this.renderingStates.FINISHED) { - // // remove loader - //} else { - // // add loader - //} } } @@ -125,7 +230,7 @@ export class PdfViewerComponent { if (!isNaN(pageInput) && pageInput > 0 && pageInput <= this.totalPages) { this.page = pageInput; - + this.displayPage = this.page; this.pdfViewer.currentPageNumber = this.page; } else { this.displayPage = this.page; diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewerHost.component.css b/ng2-components/ng2-alfresco-viewer/src/pdfViewerHost.component.css new file mode 100644 index 0000000000..eb2abd2500 --- /dev/null +++ b/ng2-components/ng2-alfresco-viewer/src/pdfViewerHost.component.css @@ -0,0 +1,202 @@ +:host .textLayer { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + overflow: hidden; + opacity: 0.2; + line-height: 1.0; +} + +:host .textLayer > div { + color: transparent; + position: absolute; + white-space: pre; + cursor: text; + -webkit-transform-origin: 0% 0%; + -moz-transform-origin: 0% 0%; + -o-transform-origin: 0% 0%; + -ms-transform-origin: 0% 0%; + transform-origin: 0% 0%; +} + +:host .textLayer .highlight { + margin: -1px; + padding: 1px; + + background-color: rgb(180, 0, 170); + border-radius: 4px; +} + +:host .textLayer .highlight.begin { + border-radius: 4px 0px 0px 4px; +} + +:host .textLayer .highlight.end { + border-radius: 0px 4px 4px 0px; +} + +:host .textLayer .highlight.middle { + border-radius: 0px; +} + +:host .textLayer .highlight.selected { + background-color: rgb(0, 100, 0); +} + +:host .textLayer ::selection { background: rgb(0,0,255); } +:host .textLayer ::-moz-selection { background: rgb(0,0,255); } + +:host .textLayer .endOfContent { + display: block; + position: absolute; + left: 0px; + top: 100%; + right: 0px; + bottom: 0px; + z-index: -1; + cursor: default; + -webkit-user-select: none; + -ms-user-select: none; + -moz-user-select: none; +} + +:host .textLayer .endOfContent.active { + top: 0px; +} + + +:host .annotationLayer section { + position: absolute; +} + +:host .annotationLayer .linkAnnotation > a { + position: absolute; + font-size: 1em; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +:host .annotationLayer .linkAnnotation > a /* -ms-a */ { + background: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7") 0 0 repeat; +} + +:host .annotationLayer .linkAnnotation > a:hover { + opacity: 0.2; + background: #ff0; + box-shadow: 0px 2px 10px #ff0; +} + +:host .annotationLayer .textAnnotation img { + position: absolute; + cursor: pointer; +} + +:host .annotationLayer .popupWrapper { + position: absolute; + width: 20em; +} + +:host .annotationLayer .popup { + position: absolute; + z-index: 200; + max-width: 20em; + background-color: #FFFF99; + box-shadow: 0px 2px 5px #333; + border-radius: 2px; + padding: 0.6em; + margin-left: 5px; + cursor: pointer; + word-wrap: break-word; +} + +:host .annotationLayer .popup h1 { + font-size: 1em; + border-bottom: 1px solid #000000; + padding-bottom: 0.2em; +} + +:host .annotationLayer .popup p { + padding-top: 0.2em; +} + +:host .annotationLayer .highlightAnnotation, +.annotationLayer .underlineAnnotation, +.annotationLayer .squigglyAnnotation, +.annotationLayer .strikeoutAnnotation, +.annotationLayer .fileAttachmentAnnotation { + cursor: pointer; +} + +:host .pdfViewer .canvasWrapper { + overflow: hidden; +} + +:host .pdfViewer .page { + direction: ltr; + width: 816px; + height: 1056px; + margin: 1px auto -8px auto; + position: relative; + overflow: visible; + border: 9px solid transparent; + background-clip: content-box; + background-color: white; +} + +:host .pdfViewer.removePageBorders .page { + margin: 0px auto 10px auto; + border: none; +} + +:host .pdfViewer .page canvas { + margin: 0; + display: block; +} + +:host .pdfViewer .page .loadingIcon { + position: absolute; + display: block; + left: 0; + top: 0; + right: 0; + bottom: 0; + background: url('images/loading-icon.gif') center no-repeat; +} + +:host * { + padding: 0; + margin: 0; +} + +:host html { + height: 100%; + width: 100%; + /* Font size is needed to make the activity bar the correct size. */ + font-size: 10px; +} + +:host body { + height: 100%; + width: 100%; + background-color: #404040; + background-image: url(images/texture.png); +} + +:host body, +input, +button, +select { + font: message-box; + outline: none; +} + +:host .hidden { + display: none !important; +} +:host [hidden] { + display: none !important; +} diff --git a/ng2-components/ng2-alfresco-viewer/src/viewer.component.css b/ng2-components/ng2-alfresco-viewer/src/viewer.component.css index a0c76b1dd5..50d9ff73bc 100644 --- a/ng2-components/ng2-alfresco-viewer/src/viewer.component.css +++ b/ng2-components/ng2-alfresco-viewer/src/viewer.component.css @@ -11,15 +11,15 @@ flex-direction: row; flex-wrap: wrap; flex: 1; - margin: 20px; } .mdl-grid { width: 100vw; + padding: 0px !important; } .viewer-name-file { - width: 20%; + width: 50%; height: 21px; overflow: hidden !important; text-overflow: ellipsis; diff --git a/ng2-components/ng2-alfresco-viewer/src/viewer.component.html b/ng2-components/ng2-alfresco-viewer/src/viewer.component.html index a7cc5c9770..7b9b379131 100644 --- a/ng2-components/ng2-alfresco-viewer/src/viewer.component.html +++ b/ng2-components/ng2-alfresco-viewer/src/viewer.component.html @@ -20,37 +20,35 @@
-
- Thumbnail -
+ + +
-
- -
+ + + + + + + -
+
- +
@@ -61,13 +59,13 @@
-
- -
+ + + + + + +
diff --git a/ng2-components/ng2-alfresco-viewer/src/viewer.component.spec.ts b/ng2-components/ng2-alfresco-viewer/src/viewer.component.spec.ts index 45418484d3..e7a32e270a 100644 --- a/ng2-components/ng2-alfresco-viewer/src/viewer.component.spec.ts +++ b/ng2-components/ng2-alfresco-viewer/src/viewer.component.spec.ts @@ -18,6 +18,7 @@ import {describe, expect, it, inject } from '@angular/core/testing'; import { TestComponentBuilder } from '@angular/compiler/testing'; import { ViewerComponent } from './viewer.component'; +import { EventMock } from './assets/event.mock'; describe('ViewerComponent', () => { @@ -97,6 +98,23 @@ import { ViewerComponent } from './viewer.component'; expect(element.querySelector('#viewer-main-container')).toBeNull(); }); })); + + it('Esc button should hide the viewer', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + return tcb + .createAsync(ViewerComponent) + .then((fixture) => { + let element = fixture.nativeElement; + let component = fixture.componentInstance; + component.urlFile = 'fake-url-file'; + + + + fixture.detectChanges(); + EventMock.keyDown(27); + fixture.detectChanges(); + expect(element.querySelector('#viewer-main-container')).toBeNull(); + }); + })); }); describe('Attribute', () => {