diff --git a/demo-shell-ng2/app/main.ts b/demo-shell-ng2/app/main.ts index 31c4a652a0..d7ae6ebc81 100644 --- a/demo-shell-ng2/app/main.ts +++ b/demo-shell-ng2/app/main.ts @@ -22,7 +22,6 @@ import { ALFRESCO_CORE_PROVIDERS } from 'ng2-alfresco-core'; import { ATIVITI_FORM_PROVIDERS } from 'ng2-activiti-form'; import { UploadService } from 'ng2-alfresco-upload'; import { AppComponent } from './app.component'; - import { appRouterProviders } from './app.routes'; bootstrap(AppComponent, [ diff --git a/demo-shell-ng2/package.json b/demo-shell-ng2/package.json index d72f45bdaf..b211986a22 100644 --- a/demo-shell-ng2/package.json +++ b/demo-shell-ng2/package.json @@ -73,7 +73,7 @@ "material-design-icons": "2.2.3", "material-design-lite": "1.1.3", "ng2-translate": "2.2.0", - "pdfjs-dist": "1.5.258", + "pdfjs-dist": "1.5.404", "flag-icon-css": "2.3.0", "intl": "1.2.4", "ng2-alfresco-core": "0.3.0", diff --git a/ng2-components/ng2-alfresco-viewer/README.md b/ng2-components/ng2-alfresco-viewer/README.md index 3de759cc6b..bb7f91e572 100644 --- a/ng2-components/ng2-alfresco-viewer/README.md +++ b/ng2-components/ng2-alfresco-viewer/README.md @@ -146,7 +146,6 @@ Attribute | Options | Default | Description | Mandatory `showViewer` | *boolean* | `true` | Hide or show the viewer | `showToolbar` | *boolean* | `true` | Hide or show the toolbars | - ## Build from sources Alternatively you can build component from sources with the following commands: diff --git a/ng2-components/ng2-alfresco-viewer/demo/src/main.ts b/ng2-components/ng2-alfresco-viewer/demo/src/main.ts index 6f62b9efa0..f21539c135 100644 --- a/ng2-components/ng2-alfresco-viewer/demo/src/main.ts +++ b/ng2-components/ng2-alfresco-viewer/demo/src/main.ts @@ -17,9 +17,7 @@ import { Component } from '@angular/core'; import { bootstrap } from '@angular/platform-browser-dynamic'; -import { VIEWERCOMPONENT } from 'ng2-alfresco-viewer'; - -import { HTTP_PROVIDERS } from '@angular/http'; +import { VIEWERCOMPONENT, RenderingQueueServices } from 'ng2-alfresco-viewer'; import { ALFRESCO_CORE_PROVIDERS, @@ -58,8 +56,9 @@ class MyDemoApp { constructor(private authService: AlfrescoAuthenticationService, private settingsService: AlfrescoSettingsService) { - settingsService.ecmHost = this.ecmHost; + settingsService.setProviders('ECM'); + if (this.authService.getTicketEcm()) { this.ticket = this.authService.getTicketEcm(); } @@ -93,6 +92,6 @@ class MyDemoApp { } bootstrap(MyDemoApp, [ VIEWERCOMPONENT, - HTTP_PROVIDERS, - ALFRESCO_CORE_PROVIDERS + ALFRESCO_CORE_PROVIDERS, + RenderingQueueServices ]); diff --git a/ng2-components/ng2-alfresco-viewer/index.ts b/ng2-components/ng2-alfresco-viewer/index.ts index e1ae5c51a8..fe53440435 100644 --- a/ng2-components/ng2-alfresco-viewer/index.ts +++ b/ng2-components/ng2-alfresco-viewer/index.ts @@ -15,7 +15,8 @@ * limitations under the License. */ -import { ViewerComponent } from './src/viewer.component'; +import { ViewerComponent } from './src/componets/viewer.component'; +import { RenderingQueueServices } from './src/services/rendering-queue.services'; /** * ng2-alfresco-viewer, provide components to view files. @@ -26,12 +27,18 @@ import { ViewerComponent } from './src/viewer.component'; * */ -export * from './src/viewer.component'; +export * from './src/componets/viewer.component'; +export * from './src/services/rendering-queue.services'; export default { - components: [ViewerComponent] + components: [ViewerComponent], + directives: [RenderingQueueServices] }; export const VIEWERCOMPONENT: [any] = [ ViewerComponent ]; + +export const ALFRESCO_VIEWER_SERVICES: [any] = [ + RenderingQueueServices +]; diff --git a/ng2-components/ng2-alfresco-viewer/karma.conf.js b/ng2-components/ng2-alfresco-viewer/karma.conf.js index 70e6adbba1..de8506166a 100644 --- a/ng2-components/ng2-alfresco-viewer/karma.conf.js +++ b/ng2-components/ng2-alfresco-viewer/karma.conf.js @@ -5,7 +5,7 @@ module.exports = function (config) { basePath: '.', - frameworks: ['jasmine'], + frameworks: ['jasmine-ajax', 'jasmine'], files: [ // paths loaded by Karma @@ -19,7 +19,9 @@ module.exports = function (config) { {pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false}, {pattern: 'node_modules/ng2-translate/**/*.js', included: false, served: true, watched: false}, {pattern: 'node_modules/alfresco-js-api/dist/alfresco-js-api.js', included: true, watched: false}, - + {pattern: 'node_modules/pdfjs-dist/build/pdf.js', included: true, watched: false}, + {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js', included: true, watched: false}, + {pattern: 'node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false}, {pattern: 'karma-test-shim.js', included: true, watched: true}, // paths loaded via module imports @@ -29,7 +31,9 @@ module.exports = function (config) { // paths to support debugging with source maps in dev tools {pattern: 'src/**/*.ts', included: false, watched: false}, - {pattern: 'dist/**/*.js.map', included: false, watched: false} + {pattern: 'dist/**/*.js.map', included: false, watched: false}, + + {pattern: 'src/assets/fake-test-file.pdf', included: false, watched: true, served: true} ], exclude: [ @@ -58,6 +62,7 @@ module.exports = function (config) { plugins: [ 'karma-jasmine', 'karma-coverage', + 'karma-jasmine-ajax', 'karma-chrome-launcher', 'karma-mocha-reporter', 'karma-jasmine-html-reporter' @@ -75,7 +80,7 @@ module.exports = function (config) { coverageReporter: { dir: 'coverage/', subdir: 'report', - reporters: [ + reporters: [ {type: 'text'}, {type: 'json', file: 'coverage-final.json'}, {type: 'html'}, diff --git a/ng2-components/ng2-alfresco-viewer/package.json b/ng2-components/ng2-alfresco-viewer/package.json index ae2eaccb66..8e80973601 100644 --- a/ng2-components/ng2-alfresco-viewer/package.json +++ b/ng2-components/ng2-alfresco-viewer/package.json @@ -68,7 +68,7 @@ "reflect-metadata": "0.1.3", "rxjs": "5.0.0-beta.6", "zone.js": "0.6.12", - "pdfjs-dist": "1.5.258" + "pdfjs-dist": "1.5.404" }, "peerDependencies": { "material-design-icons": "^2.2.3", diff --git a/ng2-components/ng2-alfresco-viewer/src/assets/PDFViewer.mock.ts b/ng2-components/ng2-alfresco-viewer/src/assets/PDFViewer.mock.ts deleted file mode 100644 index d2c597e7aa..0000000000 --- a/ng2-components/ng2-alfresco-viewer/src/assets/PDFViewer.mock.ts +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * @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 PDFViewermock { - - currentPageNumber: number = 1; - - currentPage = { - renderingState: 3 as number - }; - - _pages: any = - [{ - width: 793, - scale: 1, - update: this.update, - div: { - offsetTop: 400 - }, - viewport: { - height: 400 - } - }, { - width: 793, - scale: 1, - update: this.update, - div: { - offsetTop: 800 - }, - viewport: { - height: 400 - } - }, { - width: 793, - scale: 1, - update: this.update, - div: { - offsetTop: 1200 - }, - viewport: { - height: 400 - } - }]; - - _currentPageNumber: number = 0; - - update() { - } -} diff --git a/ng2-components/ng2-alfresco-viewer/src/assets/fake-test-file.pdf b/ng2-components/ng2-alfresco-viewer/src/assets/fake-test-file.pdf new file mode 100644 index 0000000000..1dfdeb2b8d Binary files /dev/null and b/ng2-components/ng2-alfresco-viewer/src/assets/fake-test-file.pdf differ diff --git a/ng2-components/ng2-alfresco-viewer/src/imgViewer.component.css b/ng2-components/ng2-alfresco-viewer/src/componets/imgViewer.component.css similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/imgViewer.component.css rename to ng2-components/ng2-alfresco-viewer/src/componets/imgViewer.component.css diff --git a/ng2-components/ng2-alfresco-viewer/src/imgViewer.component.html b/ng2-components/ng2-alfresco-viewer/src/componets/imgViewer.component.html similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/imgViewer.component.html rename to ng2-components/ng2-alfresco-viewer/src/componets/imgViewer.component.html diff --git a/ng2-components/ng2-alfresco-viewer/src/imgViewer.component.ts b/ng2-components/ng2-alfresco-viewer/src/componets/imgViewer.component.ts similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/imgViewer.component.ts rename to ng2-components/ng2-alfresco-viewer/src/componets/imgViewer.component.ts diff --git a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.css b/ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.css similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.css rename to ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.css diff --git a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.html b/ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.html similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.html rename to ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.html diff --git a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.spec.ts b/ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.spec.ts similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.spec.ts rename to ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.spec.ts diff --git a/ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.ts b/ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.ts similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/notSupportedFormat.component.ts rename to ng2-components/ng2-alfresco-viewer/src/componets/notSupportedFormat.component.ts diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.css b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.css similarity index 96% rename from ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.css rename to ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.css index 3cf7064098..8dc903e7ba 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.css +++ b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.css @@ -1,8 +1,3 @@ -.viewer-pdf-container { - overflow: hidden; - background: #3E3E3E; -} - .loader-container { display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */ display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */ diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.html b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.html similarity index 97% rename from ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.html rename to ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.html index 25f0a24397..5fd6b7cc79 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.html +++ b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.html @@ -4,7 +4,7 @@
-
Loading {{nameFile}} ...
+
Loading {{nameFile}} {{laodingPercent}}%
diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.spec.ts b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.spec.ts similarity index 80% rename from ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.spec.ts rename to ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.spec.ts index 70daa5cdc2..22cf97b9e8 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.spec.ts +++ b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.spec.ts @@ -15,13 +15,12 @@ * limitations under the License. */ -import {describe, expect, it, inject, beforeEachProviders, beforeEach} from '@angular/core/testing'; -import {TestComponentBuilder} from '@angular/compiler/testing'; +import { describe, expect, it, inject, beforeEachProviders, beforeEach } from '@angular/core/testing'; +import { TestComponentBuilder } from '@angular/compiler/testing'; +import { RenderingQueueServices } from '../services/rendering-queue.services'; -import {PdfViewerComponent} from './pdfViewer.component'; -import {PDFJSmock} from './assets/PDFJS.mock'; -import {PDFViewermock} from './assets/PDFViewer.mock'; -import {EventMock} from './assets/event.mock'; +import { PdfViewerComponent } from './pdfViewer.component'; +import { EventMock } from '../assets/event.mock'; import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core'; @@ -32,7 +31,8 @@ describe('PdfViewer', () => { beforeEachProviders(() => { return [ AlfrescoSettingsService, - AlfrescoAuthenticationService + AlfrescoAuthenticationService, + RenderingQueueServices ]; }); @@ -44,13 +44,8 @@ describe('PdfViewer', () => { element = fixture.nativeElement; component = fixture.componentInstance; - spyOn(component, 'getPDFJS').and.returnValue(new PDFJSmock()); - spyOn(component, 'initPDFViewer').and.callFake(() => { - component.pdfViewer = new PDFViewermock(); - }); - component.showToolbar = true; - component.urlFile = 'fake-url-file'; + component.urlFile = 'base/src/assets/fake-test-file.pdf'; pdfComponentFixture.detectChanges(); }); })); @@ -75,7 +70,6 @@ describe('PdfViewer', () => { expect(element.querySelector('#viewer-next-page-button')).not.toBeNull(); }); - it('Input Page elements should be present', () => { pdfComponentFixture.detectChanges(); @@ -102,11 +96,13 @@ describe('PdfViewer', () => { component.inputPage(1); }); - it('Total number of pages should be loaded', () => { + it('Total number of pages should be loaded', (done) => { component.ngOnChanges().then(() => { - expect(component.totalPages).toEqual('10'); + pdfComponentFixture.detectChanges(); + expect(component.totalPages).toEqual(4); + done(); }); - }); + }, 5000); it('right arrow should move to the next page', (done) => { component.ngOnChanges().then(() => { @@ -117,7 +113,7 @@ describe('PdfViewer', () => { expect(component.displayPage).toBe(2); done(); }); - }); + }, 5000); it('nextPage should move to the next page', (done) => { let nextPageButton = element.querySelector('#viewer-next-page-button'); @@ -161,7 +157,6 @@ describe('PdfViewer', () => { }); }); - /* tslint:disable:max-line-length */ it('previous page should not move to the previous page if is page 1', (done) => { component.ngOnChanges().then(() => { pdfComponentFixture.detectChanges(); @@ -177,14 +172,13 @@ describe('PdfViewer', () => { component.ngOnChanges().then(() => { pdfComponentFixture.detectChanges(); expect(component.displayPage).toBe(1); - component.inputPage('4'); + component.inputPage('2'); pdfComponentFixture.detectChanges(); - expect(component.displayPage).toBe(4); + expect(component.displayPage).toBe(2); done(); }); }); - /* tslint:disable:max-line-length */ it('zoomIn should increment the scale value', (done) => { component.currentScale = 1; @@ -194,7 +188,7 @@ describe('PdfViewer', () => { pdfComponentFixture.detectChanges(); zoomInButton.click(); expect(component.currentScaleMode).toBe('auto'); - expect(component.currentScale).toBe(1.1); + expect(component.currentScale).toBe(0.9); done(); }); }); @@ -205,20 +199,22 @@ describe('PdfViewer', () => { let zoomOutButton = element.querySelector('#viewer-zoom-out-button'); component.ngOnChanges().then(() => { + component.inputPage('1'); pdfComponentFixture.detectChanges(); zoomOutButton.click(); expect(component.currentScaleMode).toBe('auto'); - expect(component.currentScale).toBe(0.9); + expect(component.currentScale).toBe(0.7); done(); }); }); - it('fit in button should toggle page-fit and auto scale mode', (done) => { + it('fit-in button should toggle page-fit and auto scale mode', (done) => { component.currentScale = 1; let fitPage = element.querySelector('#viewer-scale-page-button'); component.ngOnChanges().then(() => { + component.inputPage('1'); pdfComponentFixture.detectChanges(); expect(component.currentScaleMode).toBe('auto'); fitPage.click(); @@ -227,20 +223,19 @@ describe('PdfViewer', () => { expect(component.currentScaleMode).toBe('auto'); done(); }); - }); + }, 5000); }); describe('Resize interaction', () => { - it('resize event should trigger setScaleUpdatePages', () => { - 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(); + it('resize event should trigger setScaleUpdatePages', (done) => { + component.ngOnChanges().then(() => { + pdfComponentFixture.detectChanges(); + spyOn(component, 'onResize'); + component.documentContainer = element.querySelector('#viewer-pdf-container'); + EventMock.resizeMobileView(); + expect(component.onResize).toHaveBeenCalled(); + done(); + }, 5000); }); }); @@ -249,10 +244,13 @@ describe('PdfViewer', () => { component.ngOnChanges().then(() => { pdfComponentFixture.detectChanges(); expect(component.displayPage).toBe(1); - component.inputPage('4'); + component.inputPage('2'); + pdfComponentFixture.detectChanges(); + expect(component.displayPage).toBe(2); + let documentContainer = element.querySelector('#viewer-pdf-container'); + documentContainer.scrollTop = 100000; + component.watchScroll(documentContainer); pdfComponentFixture.detectChanges(); - expect(component.displayPage).toBe(4); - component.watchScroll({scrollTop: 10000}); expect(component.displayPage).toBe(4); done(); }); diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.ts b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.ts similarity index 92% rename from ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.ts rename to ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.ts index 6f2d5f2389..c9750c7231 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewer.component.ts +++ b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewer.component.ts @@ -16,6 +16,7 @@ */ import { Component, Input, HostListener } from '@angular/core'; +import { RenderingQueueServices } from '../services/rendering-queue.services'; declare let PDFJS: any; declare let __moduleName: string; @@ -24,7 +25,8 @@ declare let __moduleName: string; moduleId: __moduleName, selector: 'pdf-viewer', templateUrl: './pdfViewer.component.html', - styleUrls: ['./pdfViewer.component.css', './pdfViewerHost.component.css'] + styleUrls: ['./pdfViewer.component.css', './pdfViewerHost.component.css'], + providers: [RenderingQueueServices] }) export class PdfViewerComponent { @@ -37,10 +39,12 @@ export class PdfViewerComponent { @Input() showToolbar: boolean = true; + currentPdfDocument: any; page: number; displayPage: number; totalPages: number; + laodingPercent: number; pdfViewer: any; @@ -52,6 +56,9 @@ export class PdfViewerComponent { MIN_SCALE: number = 0.25; MAX_SCALE: number = 10.0; + constructor(private renderingQueueServices: RenderingQueueServices) { + } + ngOnChanges(changes) { if (!this.urlFile) { throw new Error('Attribute urlFile is required'); @@ -59,7 +66,14 @@ export class PdfViewerComponent { if (this.urlFile) { return new Promise((resolve, reject) => { - this.getPDFJS().getDocument(this.urlFile, null, null).then((pdfDocument) => { + let loadingTask = this.getPDFJS().getDocument(this.urlFile); + + loadingTask.onProgress = (progressData) => { + let level = progressData.loaded / progressData.total; + this.laodingPercent = Math.round(level * 100); + }; + + loadingTask.then((pdfDocument) => { this.currentPdfDocument = pdfDocument; this.totalPages = pdfDocument.numPages; this.page = 1; @@ -68,6 +82,7 @@ export class PdfViewerComponent { this.currentPdfDocument.getPage(1).then(() => { this.scalePage('auto'); + resolve(); }, (error) => { reject(error); }); @@ -75,7 +90,6 @@ export class PdfViewerComponent { }, (error) => { reject(error); }); - resolve(); }); } } @@ -90,7 +104,7 @@ export class PdfViewerComponent { } initPDFViewer(pdfDocument: any) { - PDFJS.verbosity = 5; + PDFJS.verbosity = 1; PDFJS.disableWorker = true; let documentContainer = document.getElementById('viewer-pdf-container'); @@ -102,9 +116,12 @@ export class PdfViewerComponent { this.pdfViewer = new PDFJS.PDFViewer({ container: documentContainer, - viewer: viewer + viewer: viewer, + renderingQueue: this.renderingQueueServices }); + this.renderingQueueServices.setViewer(this.pdfViewer); + this.pdfViewer.setDocument(pdfDocument); } @@ -313,6 +330,7 @@ export class PdfViewerComponent { */ watchScroll(target) { let outputPage = this.getVisibleElement(target); + if (outputPage) { this.page = outputPage.id; this.displayPage = this.page; diff --git a/ng2-components/ng2-alfresco-viewer/src/pdfViewerHost.component.css b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewerHost.component.css similarity index 72% rename from ng2-components/ng2-alfresco-viewer/src/pdfViewerHost.component.css rename to ng2-components/ng2-alfresco-viewer/src/componets/pdfViewerHost.component.css index eb2abd2500..72a00ab41d 100644 --- a/ng2-components/ng2-alfresco-viewer/src/pdfViewerHost.component.css +++ b/ng2-components/ng2-alfresco-viewer/src/componets/pdfViewerHost.component.css @@ -164,7 +164,52 @@ top: 0; right: 0; bottom: 0; - background: url('images/loading-icon.gif') center no-repeat; +} + +:host .loadingIcon { + width: 100px; + height: 100px; + left: 50% !important; + top: 50% !important; + + margin-top: -50px; + margin-left: -50px; + + font-size: 5px; + text-indent: -9999em; + border-top: 1.1em solid rgba(3,0,2, 0.2); + border-right: 1.1em solid rgba(3,0,2, 0.2); + border-bottom: 1.1em solid rgba(3,0,2, 0.2); + border-left: 1.1em solid #030002; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-animation: load8 1.1s infinite linear; + animation: load8 1.1s infinite linear; +} +:host .loadingIcon, +:host .loadingIcon:after { + border-radius: 50%; +} +@-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } } :host * { @@ -200,3 +245,21 @@ select { :host [hidden] { display: none !important; } + + +#viewer-pdf-container { + overflow: auto; + -webkit-overflow-scrolling: touch; + position: absolute; + top: 32px; + right: 0; + bottom: 0; + left: 0; + outline: none; +} +html[dir='ltr'] #viewer-pdf-container { + box-shadow: inset 1px 0 0 hsla(0,0%,100%,.05); +} +html[dir='rtl'] #viewer-pdf-container { + box-shadow: inset -1px 0 0 hsla(0,0%,100%,.05); +} diff --git a/ng2-components/ng2-alfresco-viewer/src/viewer.component.css b/ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.css similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/viewer.component.css rename to ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.css diff --git a/ng2-components/ng2-alfresco-viewer/src/viewer.component.html b/ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.html similarity index 100% rename from ng2-components/ng2-alfresco-viewer/src/viewer.component.html rename to ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.html diff --git a/ng2-components/ng2-alfresco-viewer/src/viewer.component.spec.ts b/ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.spec.ts similarity index 72% rename from ng2-components/ng2-alfresco-viewer/src/viewer.component.spec.ts rename to ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.spec.ts index a54433b541..1484213c9a 100644 --- a/ng2-components/ng2-alfresco-viewer/src/viewer.component.spec.ts +++ b/ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.spec.ts @@ -15,11 +15,14 @@ * limitations under the License. */ -import {describe, expect, it, inject, beforeEachProviders, beforeEach} from '@angular/core/testing'; -import {TestComponentBuilder} from '@angular/compiler/testing'; -import {ViewerComponent} from './viewer.component'; -import {EventMock} from './assets/event.mock'; -import {AlfrescoAuthenticationService, AlfrescoSettingsService} from 'ng2-alfresco-core'; +import { describe, expect, it, inject, beforeEachProviders, beforeEach, afterEach } from '@angular/core/testing'; +import { TestComponentBuilder } from '@angular/compiler/testing'; +import { ViewerComponent } from './viewer.component'; +import { EventMock } from '../assets/event.mock'; +import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core'; +import { RenderingQueueServices } from '../services/rendering-queue.services'; + +declare let jasmine: any; describe('ViewerComponent', () => { @@ -28,7 +31,8 @@ describe('ViewerComponent', () => { beforeEachProviders(() => { return [ AlfrescoSettingsService, - AlfrescoAuthenticationService + AlfrescoAuthenticationService, + RenderingQueueServices ]; }); @@ -40,13 +44,20 @@ describe('ViewerComponent', () => { element = viewerComponentFixture.nativeElement; component = viewerComponentFixture.componentInstance; - component.urlFile = 'fake-url-file'; + jasmine.Ajax.install(); + + component.urlFile = 'base/src/assets/fake-test-file.pdf'; + component.overlayMode = true; viewerComponentFixture.detectChanges(); }); })); + afterEach(() => { + jasmine.Ajax.uninstall(); + }); + describe('View', () => { it('shadow overlay should be present if is overlay mode', () => { expect(element.querySelector('#viewer-shadow-transparent')).not.toBeNull(); @@ -65,17 +76,15 @@ describe('ViewerComponent', () => { }); it('Name File should be present if is overlay mode ', () => { - component.urlFile = 'http://localhost:9876/fake-url-file.pdf'; component.overlayMode = true; component.ngOnChanges().then(() => { viewerComponentFixture.detectChanges(); - expect(element.querySelector('#viewer-name-file').innerHTML).toEqual('fake-url-file.pdf'); + expect(element.querySelector('#viewer-name-file').innerHTML).toEqual('fake-test-file.pdf'); }); }); it('Close button should be present if overlay mode', () => { - component.urlFile = 'fake-url-file'; component.overlayMode = true; viewerComponentFixture.detectChanges(); @@ -84,7 +93,6 @@ describe('ViewerComponent', () => { }); it('Close button should be not present if is not overlay mode', () => { - component.urlFile = 'fake-url-file'; component.overlayMode = false; viewerComponentFixture.detectChanges(); @@ -93,7 +101,6 @@ describe('ViewerComponent', () => { }); it('Click on close button should hide the viewer', () => { - component.urlFile = 'fake-url-file'; component.overlayMode = true; viewerComponentFixture.detectChanges(); @@ -106,8 +113,6 @@ describe('ViewerComponent', () => { it('Esc button should not hide the viewerls if is not overlay mode', () => { component.overlayMode = false; - component.urlFile = 'fake-url-file'; - viewerComponentFixture.detectChanges(); EventMock.keyDown(27); viewerComponentFixture.detectChanges(); @@ -115,7 +120,6 @@ describe('ViewerComponent', () => { }); it('Esc button should hide the viewer', () => { - component.urlFile = 'fake-url-file'; component.overlayMode = true; viewerComponentFixture.detectChanges(); @@ -127,8 +131,9 @@ describe('ViewerComponent', () => { }); describe('Attribute', () => { - it('Url File should be mandatory', () => { + it('Url or fileNodeId File should be mandatory', () => { component.showViewer = true; + component.fileNodeId = undefined; component.urlFile = undefined; expect(() => { @@ -136,12 +141,53 @@ describe('ViewerComponent', () => { }).toThrow(); }); + it('If FileNodeId is present should not be thrown any error ', () => { + component.showViewer = true; + component.fileNodeId = 'file-node-id'; + component.urlFile = undefined; + + expect(() => { + component.ngOnChanges(); + }).not.toThrow(); + }); + + it('If urlFile is present should not be thrown any error ', () => { + component.showViewer = true; + component.fileNodeId = undefined; + + expect(() => { + component.ngOnChanges(); + }).not.toThrow(); + }); + + it('If FileNodeId is present the node api should be called', (done) => { + component.showViewer = true; + component.fileNodeId = 'file-node-id'; + component.urlFile = undefined; + + jasmine.Ajax.stubRequest( + 'http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/file-node-id' + ).andReturn({ + status: 200, + responseText: '{"entry":{"isFile":true,"createdByUser":{"id":"admin","displayName":"Administrator"},' + + '"modifiedAt":"2016-08-05T23:08:22.730+0000","nodeType":"cm:content","content":' + + '{"mimeType":"application/pdf","mimeTypeName":"Adobe PDF Document","sizeInBytes":' + + '381778,"encoding":"UTF-8"},"parentId":"8f2105b4-daaf-4874-9e8a-2152569d109b","createdAt":"2016-08-05T23:08:22.730+0000","isFolder":false,' + + '"modifiedByUser":{"id":"admin","displayName":"Administrator"},"name":"content.pdf","id":' + + '"b8bd4c81-6f2e-4ec2-9c4d-30c97cf42bc8"}}' + }); + + component.ngOnChanges().then(() => { + expect(jasmine.Ajax.requests.mostRecent().url.endsWith('nodes/file-node-id')).toBe(true); + done(); + }); + }); + it('showViewer default value should be true', () => { expect(component.showViewer).toBe(true); }); it('if showViewer value is false the viewer should be hide', () => { - component.urlFile = 'fake-url-file'; component.showViewer = false; viewerComponentFixture.detectChanges(); @@ -151,7 +197,7 @@ describe('ViewerComponent', () => { describe('Extension Type Test', () => { it('if extension file is a pdf the pdf viewer should be loaded', (done) => { - component.urlFile = 'fake-url-file.pdf'; + component.urlFile = 'base/src/assets/fake-test-file.pdf'; component.ngOnChanges().then(() => { viewerComponentFixture.detectChanges(); diff --git a/ng2-components/ng2-alfresco-viewer/src/viewer.component.ts b/ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.ts similarity index 93% rename from ng2-components/ng2-alfresco-viewer/src/viewer.component.ts rename to ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.ts index 893aa4f71f..aaf6ba75d5 100644 --- a/ng2-components/ng2-alfresco-viewer/src/viewer.component.ts +++ b/ng2-components/ng2-alfresco-viewer/src/componets/viewer.component.ts @@ -20,7 +20,7 @@ import { PdfViewerComponent } from './pdfViewer.component'; import { ImgViewerComponent } from './imgViewer.component'; import { NotSupportedFormat } from './notSupportedFormat.component'; import { DOCUMENT } from '@angular/platform-browser'; -import { AlfrescoAuthenticationService} from 'ng2-alfresco-core'; +import { AlfrescoAuthenticationService } from 'ng2-alfresco-core'; declare let __moduleName: string; @@ -34,7 +34,7 @@ declare let __moduleName: string; export class ViewerComponent { @Input() - urlFile: string; + urlFile: string = ''; @Input() fileNodeId: string = null; @@ -73,25 +73,25 @@ export class ViewerComponent { if (!this.urlFile && !this.fileNodeId) { throw new Error('Attribute urlFile or fileNodeId is required'); } - return new Promise((resolve) => { + return new Promise((resolve, reject) => { if (this.urlFile) { let filenameFromUrl = this.getFilenameFromUrl(this.urlFile); this.displayName = filenameFromUrl ? filenameFromUrl : ''; this.extension = this.getFileExtension(filenameFromUrl); this.urlFileContent = this.urlFile; + resolve(); } else if (this.fileNodeId) { this.authService.getAlfrescoApi().nodes.getNodeInfo(this.fileNodeId).then((data) => { this.mimeType = data.content.mimeType; this.displayName = data.name; this.urlFileContent = this.authService.getAlfrescoApi().content.getContentUrl(data.id); this.loaded = true; + resolve(); }, function (error) { + reject(error); console.log('This node does not exist'); }); } - - - resolve(); }); } } @@ -104,10 +104,24 @@ export class ViewerComponent { if (this.otherMenu) { this.otherMenu.hidden = false; } + this.cleanup(); this.showViewer = false; this.showViewerChange.emit(this.showViewer); } + cleanup() { + this.urlFileContent = ''; + this.displayName = ''; + this.fileNodeId = null; + this.loaded = false; + this.extension = null; + this.mimeType = null; + } + + ngOnDestroy() { + this.cleanup(); + } + /** * get File name from url * diff --git a/ng2-components/ng2-alfresco-viewer/src/services/rendering-queue.services.spec.ts b/ng2-components/ng2-alfresco-viewer/src/services/rendering-queue.services.spec.ts new file mode 100644 index 0000000000..04c6863317 --- /dev/null +++ b/ng2-components/ng2-alfresco-viewer/src/services/rendering-queue.services.spec.ts @@ -0,0 +1,39 @@ +/*! + * @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 { it, describe, inject, beforeEach, beforeEachProviders, expect } from '@angular/core/testing'; +import { RenderingQueueServices } from './rendering-queue.services'; + + +describe('RenderingQueueServices', () => { + + let service; + + beforeEachProviders(() => { + return [ + RenderingQueueServices + ]; + }); + + beforeEach(inject([RenderingQueueServices], (renderingQueueServices: RenderingQueueServices) => { + service = renderingQueueServices; + })); + + it('Simple import example', () => { + expect(service.CLEANUP_TIMEOUT).toEqual(30000); + }); +}); diff --git a/ng2-components/ng2-alfresco-viewer/src/services/rendering-queue.services.ts b/ng2-components/ng2-alfresco-viewer/src/services/rendering-queue.services.ts new file mode 100644 index 0000000000..bf8c0c2e2b --- /dev/null +++ b/ng2-components/ng2-alfresco-viewer/src/services/rendering-queue.services.ts @@ -0,0 +1,171 @@ +/*! + * @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 { Injectable } from '@angular/core'; + +/** + * + * RenderingQueueServices rendering of the views for pages and thumbnails. + * + * @returns {RenderingQueueServices} . + */ +@Injectable() +export class RenderingQueueServices { + + renderingStates = { + INITIAL: 0, + RUNNING: 1, + PAUSED: 2, + FINISHED: 3 + }; + + CLEANUP_TIMEOUT: number = 30000; + + pdfViewer: any = null; + pdfThumbnailViewer: any = null; + onIdle: any = null; + + highestPriorityPage: any = null; + idleTimeout: any = null; + printing: any = false; + isThumbnailViewEnabled: any = false; + + /** + * @param {PDFViewer} pdfViewer + */ + setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + } + + /** + * @param {PDFThumbnailViewer} pdfThumbnailViewer + */ + setThumbnailViewer(pdfThumbnailViewer) { + this.pdfThumbnailViewer = pdfThumbnailViewer; + } + + /** + * @param {IRenderableView} view + * @returns {boolean} + */ + isHighestPriority(view: any) { + return this.highestPriorityPage === view.renderingId; + } + + renderHighestPriority(currentlyVisiblePages) { + if (this.idleTimeout) { + clearTimeout(this.idleTimeout); + this.idleTimeout = null; + } + + // Pages have a higher priority than thumbnails, so check them first. + if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { + return; + } + // No pages needed rendering so check thumbnails. + if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) { + if (this.pdfThumbnailViewer.forceRendering()) { + return; + } + } + + if (this.printing) { + // If printing is currently ongoing do not reschedule cleanup. + return; + } + + if (this.onIdle) { + this.idleTimeout = setTimeout(this.onIdle.bind(this), this.CLEANUP_TIMEOUT); + } + } + + getHighestPriority(visible, views, scrolledDown) { + // The state has changed figure out which page has the highest priority to + // render next (if any). + // Priority: + // 1 visible pages + // 2 if last scrolled down page after the visible pages + // 2 if last scrolled up page before the visible pages + let visibleViews = visible.views; + + let numVisible = visibleViews.length; + if (numVisible === 0) { + return false; + } + for (let i = 0; i < numVisible; ++i) { + let view = visibleViews[i].view; + if (!this.isViewFinished(view)) { + return view; + } + } + + // All the visible views have rendered, try to render next/previous pages. + if (scrolledDown) { + let nextPageIndex = visible.last.id; + // ID's start at 1 so no need to add 1. + if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) { + return views[nextPageIndex]; + } + } else { + let previousPageIndex = visible.first.id - 2; + if (views[previousPageIndex] && !this.isViewFinished(views[previousPageIndex])) { + return views[previousPageIndex]; + } + } + // Everything that needs to be rendered has been. + return null; + } + + /** + * @param {IRenderableView} view + * @returns {boolean} + */ + isViewFinished(view) { + return view.renderingState === this.renderingStates.FINISHED; + } + + /** + * Render a page or thumbnail view. This calls the appropriate function + * based on the views state. If the view is already rendered it will return + * false. + * @param {IRenderableView} view + */ + renderView(view: any) { + let state = view.renderingState; + switch (state) { + case this.renderingStates.FINISHED: + return false; + case this.renderingStates.PAUSED: + this.highestPriorityPage = view.renderingId; + view.resume(); + break; + case this.renderingStates.RUNNING: + this.highestPriorityPage = view.renderingId; + break; + case this.renderingStates.INITIAL: + this.highestPriorityPage = view.renderingId; + let continueRendering = function () { + this.renderHighestPriority(); + }.bind(this); + view.draw().then(continueRendering, continueRendering); + break; + default: + break; + } + return true; + } +}