diff --git a/static/js/directives/directives.js b/static/js/directives/directives.js index 98667aff..de78b0a8 100644 --- a/static/js/directives/directives.js +++ b/static/js/directives/directives.js @@ -38,7 +38,8 @@ define([ 'directives/page', 'directives/contactrequest', 'directives/defaultdialog', - 'directives/pdfviewer'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPicture, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfviewer) { + 'directives/pdfcanvas', + 'directives/pdfviewer'], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPicture, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfcanvas, pdfviewer) { var directives = { onEnter: onEnter, @@ -58,6 +59,7 @@ define([ page: page, contactRequest: contactRequest, defaultDialog: defaultDialog, + pdfcanvas: pdfcanvas, pdfviewer: pdfviewer }; diff --git a/static/js/directives/pdfcanvas.js b/static/js/directives/pdfcanvas.js new file mode 100644 index 00000000..7028f7ad --- /dev/null +++ b/static/js/directives/pdfcanvas.js @@ -0,0 +1,209 @@ +/* + * Spreed WebRTC. + * Copyright (C) 2013-2014 struktur AG + * + * This file is part of Spreed WebRTC. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +define(['require', 'underscore', 'jquery', 'pdf'], function(require, _, $, pdf) { + + pdf.workerSrc = require.toUrl('pdf.worker') + ".js"; + + return ["$compile", function($compile) { + + var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { + + var PDFCanvas = function(scope, scale, canvases) { + this.scope = scope; + this.canvases = canvases; + this.doc = null; + this.rendering = false; + this.scale = scale; + this.currentPage = null; + this.pendingPageNumber = null; + }; + + PDFCanvas.prototype.close = function() { + if (this.currentPage) { + this.currentPage.destroy(); + this.currentPage = null; + } + if (this.doc) { + this.doc.cleanup(); + this.doc.destroy(); + this.doc = null; + } + this.rendering = false; + this.pendingPageNumber = null; + this.scope.currentPageNumber = -1; + this.scope.maxPageNumber = -1; + // clear visible canvas so it's empty when we show the next document + var canvas = this.canvases[this.scope.canvasIndex]; + canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); + this.scope.$emit("pdfClosed"); + }; + + PDFCanvas.prototype.open = function(file) { + console.log("Loading PDF from", file); + if (typeof file === "string") { + // got a url + this._openFile(file); + return; + } + + var fp = file.file || file; + if (typeof URL !== "undefined" && URL.createObjectURL) { + var url = URL.createObjectURL(fp); + this._openFile(url); + } else { + var fileReader = new FileReader(); + fileReader.onload = _.bind(function(evt) { + var buffer = evt.target.result; + var uint8Array = new Uint8Array(buffer); + this._openFile(uint8Array); + }, this); + fileReader.readAsArrayBuffer(fp); + } + }; + + PDFCanvas.prototype._openFile = function(source) { + this.scope.$emit("pdfLoading", source); + pdf.getDocument(source).then(_.bind(function(doc) { + this.scope.$apply(_.bind(function(scope) { + this.doc = doc; + scope.maxPageNumber = doc.numPages; + scope.currentPageNumber = -1; + console.log("PDF loaded", doc); + scope.$emit("pdfLoaded", source, doc); + }, this)); + }, this)); + }; + + PDFCanvas.prototype._showPage = function(page) { + console.log("Showing page", page, "/", this.scope.maxPageNumber); + if (this.currentPage) { + this.currentPage.destroy(); + this.currentPage = null; + } + this.rendering = true; + this.scope.currentPageNumber = page; + this.scope.$emit("pdfPageLoading", page); + this.doc.getPage(page).then(_.bind(function(pageObject) { + console.log("Got page", pageObject); + this.scope.$emit("pdfPageLoaded", page, pageObject); + this.currentPage = pageObject; + var viewport = pageObject.getViewport(this.scale); + // use double-buffering to avoid flickering while + // the new page is rendered... + var canvas = this.canvases[1 - this.scope.canvasIndex]; + canvas.width = viewport.width; + canvas.height = viewport.height; + var renderContext = { + canvasContext: canvas.getContext("2d"), + viewport: viewport + }; + + console.log("Rendering page", pageObject); + this.scope.$emit("pdfPageRendering", page); + // TODO(fancycode): also render images in different resolutions for subscribed peers and send to them when ready + var renderTask = pageObject.render(renderContext); + renderTask.promise.then(_.bind(function() { + this.scope.$apply(_.bind(function(scope) { + console.log("Rendered page", page); + this.scope.$emit("pdfPageRendered", page, scope.maxPageNumber); + this.rendering = false; + // ...and flip the buffers... + scope.canvasIndex = 1 - scope.canvasIndex; + this.showQueuedPage(); + }, this)); + }, this)); + }, this)); + }; + + PDFCanvas.prototype.showPage = function(page) { + if (page >= 1 && page <= this.scope.maxPageNumber) { + if (!this.doc || this.rendering) { + this.pendingPageNumber = page; + } else { + this._showPage(page); + } + } + }; + + PDFCanvas.prototype.prevPage = function() { + this.showPage(this.scope.currentPageNumber - 1); + }; + + PDFCanvas.prototype.nextPage = function() { + this.showPage(this.scope.currentPageNumber + 1); + }; + + PDFCanvas.prototype.showQueuedPage = function() { + if (this.pendingPageNumber !== null) { + this._showPage(this.pendingPageNumber); + this.pendingPageNumber = null; + } + }; + + $scope.currentPageNumber = -1; + $scope.maxPageNumber = -1; + $scope.canvasIndex = 0; + + var canvases = $element.find("canvas"); + var scale = 0.8; + var pdfCanvas = new PDFCanvas($scope, scale, canvases); + + $scope.$on("openPdf", function(event, source) { + pdfCanvas.open(source); + }); + + $scope.$on("closePdf", function() { + pdfCanvas.close(); + }); + + $scope.$on("$destroy", function() { + pdfCanvas.close(); + pdfCanvas = null; + }); + + $scope.$on("showPdfPage", function(event, page) { + pdfCanvas.showPage(page); + }); + + $scope.$on("showQueuedPdfPage", function() { + pdfCanvas.showQueuedPage(); + }); + + $scope.prevPage = function() { + pdfCanvas.prevPage(); + }; + + $scope.nextPage = function() { + pdfCanvas.nextPage(); + }; + + }]; + + return { + restrict: 'E', + replace: true, + template: '', + controller: controller + }; + + }]; + +}); diff --git a/static/js/directives/pdfviewer.js b/static/js/directives/pdfviewer.js index cf1ed855..52742d25 100644 --- a/static/js/directives/pdfviewer.js +++ b/static/js/directives/pdfviewer.js @@ -18,9 +18,7 @@ * along with this program. If not, see . * */ -define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf'], function(require, $, _, template, pdf) { - - pdf.workerSrc = require.toUrl('pdf.worker') + ".js"; +define(['jquery', 'underscore', 'text!partials/pdfviewer.html'], function($, _, template) { return ["$window", "mediaStream", "fileUpload", "fileDownload", "alertify", "translation", "randomGen", function($window, mediaStream, fileUpload, fileDownload, alertify, translation, randomGen) { @@ -28,20 +26,18 @@ define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf' var pdfViewerCount = 0; var pane = $element.find(".pdfviewerpane"); - var canvases = $element.find(".pdfviewercanvas"); - $scope.canvasIndex = 0; $scope.layout.pdfviewer = false; $scope.isPresenter = false; $scope.hideControlsBar = false; - $scope.doc = null; - $scope.rendering = false; - $scope.scale = 0.8; - $scope.currentPage = null; - $scope.currentPageNumber = -1; - $scope.maxPageNumber = -1; - $scope.pendingPageNumber = null; + $scope.$on("pdfLoaded", function(event, source, doc) { + if ($scope.isPresenter) { + $scope.$emit("showPdfPage", 1); + } else { + $scope.$emit("showQueuedPdfPage"); + } + }); var handleRequest = function(event, currenttoken, to, data, type, to2, from, peerpdfviewer) { console.log("PdfViewer answer message", currenttoken, data, type); @@ -71,10 +67,10 @@ define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf' subscope.$on("writeComplete", function(event, url, fileInfo) { event.stopPropagation(); if (url.indexOf("blob:") === 0) { - $scope.doOpenFile(url); + $scope.$emit("openPdf", url); } else { fileInfo.file.file(function(fp) { - $scope.openFile(fp); + $scope.$emit("openPdf", fp); }); } }); @@ -86,7 +82,7 @@ define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf' break; case "Page": - $scope.$emit("queuePageRendering", data.Page); + $scope.$emit("showPdfPage", data.Page); break; default: @@ -95,104 +91,6 @@ define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf' } }); - $scope.showPage = function(page) { - console.log("Showing page", page, "/", $scope.maxPageNumber); - if ($scope.currentPage) { - $scope.currentPage.destroy(); - $scope.currentPage = null; - } - $scope.rendering = true; - $scope.currentPageNumber = page; - $scope.doc.getPage(page).then(function(page) { - console.log("Got page", page); - $scope.currentPage = page; - var viewport = page.getViewport($scope.scale); - // use double-buffering to avoid flickering while - // the new page is rendered... - var canvas = canvases[1 - $scope.canvasIndex]; - canvas.width = viewport.width; - canvas.height = viewport.height; - var renderContext = { - canvasContext: canvas.getContext("2d"), - viewport: viewport - }; - - console.log("Rendering page", page); - // TODO(fancycode): also render images in different resolutions for subscribed peers and send to them when ready - var renderTask = page.render(renderContext); - renderTask.promise.then(function() { - $scope.$apply(function(scope) { - console.log("Rendered page", page); - scope.rendering = false; - // ...and flip the buffers... - scope.canvasIndex = 1 - scope.canvasIndex; - console.log("Done"); - scope.showQueuedPage(); - }); - }); - }); - }; - - $scope.$on("queuePageRendering", function(event, page) { - if (!$scope.doc || $scope.rendering) { - $scope.pendingPageNumber = page; - } else { - $scope.showPage(page); - } - }); - - $scope.prevPage = function() { - if ($scope.currentPageNumber > 1) { - $scope.$emit("queuePageRendering", $scope.currentPageNumber - 1); - } - }; - - $scope.nextPage = function() { - if ($scope.currentPageNumber < $scope.maxPageNumber) { - $scope.$emit("queuePageRendering", $scope.currentPageNumber + 1); - } - }; - - $scope.showQueuedPage = function() { - if ($scope.pendingPageNumber !== null) { - $scope.showPage($scope.pendingPageNumber); - $scope.pendingPageNumber = null; - } - }; - - $scope.doOpenFile = function(source) { - pdf.getDocument(source).then(function(doc) { - $scope.$apply(function(scope) { - scope.doc = doc; - scope.maxPageNumber = doc.numPages; - scope.currentPageNumber = -1; - console.log("PDF loaded", doc); - if ($scope.isPresenter) { - scope.$emit("queuePageRendering", 1); - } else { - scope.showQueuedPage(); - } - }); - }); - }; - - $scope.openFile = function(file) { - console.log("Loading PDF from", file); - var fp = file.file || file; - if (typeof URL !== "undefined" && URL.createObjectURL) { - var url = URL.createObjectURL(fp); - $scope.doOpenFile(url); - } else { - var fileReader = new FileReader(); - fileReader.onload = function webViewerChangeFileReaderOnload(evt) { - var buffer = evt.target.result; - var uint8Array = new Uint8Array(buffer); - $scope.doOpenFile(uint8Array); - }; - fileReader.readAsArrayBuffer(fp); - } - }; - $scope.showPDFViewer = function() { console.log("PDF viewer active"); if ($scope.layout.pdfviewer) { @@ -257,7 +155,7 @@ define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf' // Catch later calls too. mediaStream.webrtc.e.on("statechange", updater); - $scope.$on("queuePageRendering", function(event, page) { + $scope.$on("pdfPageLoading", function(event, page) { _.each(peers, function(ignore, peerId) { var peercall = mediaStream.webrtc.findTargetCall(peerId); mediaStream.api.apply("sendPdfViewer", { @@ -311,7 +209,7 @@ define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf' session.handleRequest(subscope, xfer, data); }, "xfer"); $scope.isPresenter = true; - $scope.openFile(f); + $scope.$emit("openPdf", f); }, this)); }, this)); binder.namespace = function() { @@ -323,14 +221,7 @@ define(['require', 'jquery', 'underscore', 'text!partials/pdfviewer.html', 'pdf' $scope.hidePDFViewer = function() { console.log("PDF viewer disabled"); - if ($scope.doc) { - $scope.doc.cleanup(); - $scope.doc.destroy(); - $scope.doc = null; - } - // clear visible canvas so it's empty when we show the next document - var canvas = canvases[$scope.canvasIndex]; - canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); + $scope.$emit("closePdf"); $scope.layout.pdfviewer = false; $scope.isPresenter = false; $scope.$emit("mainview", "pdfviewer", false); diff --git a/static/partials/pdfviewer.html b/static/partials/pdfviewer.html index f2545169..81ec03bf 100644 --- a/static/partials/pdfviewer.html +++ b/static/partials/pdfviewer.html @@ -1,7 +1,6 @@
- - +