6 changed files with 501 additions and 344 deletions
@ -0,0 +1,314 @@
@@ -0,0 +1,314 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
||||
/* Copyright 2014 Mozilla Foundation |
||||
* |
||||
* 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. |
||||
*/ |
||||
/*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE, |
||||
IGNORE_CURRENT_POSITION_ON_ZOOM, SCROLLBAR_PADDING, VERTICAL_PADDING, |
||||
MAX_AUTO_SCALE, getVisibleElements, PresentationMode, |
||||
RenderingStates */ |
||||
|
||||
'use strict'; |
||||
|
||||
var PDFViewer = (function pdfViewer() { |
||||
function PDFViewer(options) { |
||||
this.container = options.container; |
||||
this.viewer = options.viewer; |
||||
this.renderingQueue = options.renderingQueue; |
||||
this.linkService = options.linkService; |
||||
|
||||
this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this)); |
||||
this.pages = []; |
||||
this.cache = new Cache(DEFAULT_CACHE_SIZE); |
||||
this.currentPageNumber = 1; |
||||
this.previousPageNumber = 1; |
||||
this.updateInProgress = true; |
||||
this.resetView(); |
||||
} |
||||
|
||||
PDFViewer.prototype = { |
||||
get pagesCount() { |
||||
return this.pages.length; |
||||
}, |
||||
|
||||
setCurrentPageNumber: function (val) { |
||||
var event = document.createEvent('UIEvents'); |
||||
event.initUIEvent('pagechange', true, true, window, 0); |
||||
event.updateInProgress = this.updateInProgress; |
||||
|
||||
if (!(0 < val && val <= this.pagesCount)) { |
||||
this.previousPageNumber = val; |
||||
event.pageNumber = this.page; |
||||
this.container.dispatchEvent(event); |
||||
return; |
||||
} |
||||
|
||||
this.pages[val - 1].updateStats(); |
||||
this.previousPageNumber = this.currentPageNumber; |
||||
this.currentPageNumber = val; |
||||
event.pageNumber = val; |
||||
this.container.dispatchEvent(event); |
||||
}, |
||||
|
||||
addPage: function (pageNum, scale, viewport) { |
||||
var pageView = new PageView(this.viewer, pageNum, scale, viewport, |
||||
this.linkService, this.renderingQueue, |
||||
this.cache, this); |
||||
this.pages.push(pageView); |
||||
return pageView; |
||||
}, |
||||
|
||||
resetView: function () { |
||||
this.currentScale = UNKNOWN_SCALE; |
||||
this.currentScaleValue = null; |
||||
this.location = null; |
||||
}, |
||||
|
||||
_scrollUpdate: function () { |
||||
if (this.pagesCount === 0) { |
||||
return; |
||||
} |
||||
this.update(); |
||||
}, |
||||
|
||||
_setScaleUpdatePages: function pdfViewer_setScaleUpdatePages( |
||||
newScale, newValue, resetAutoSettings, noScroll, preset) { |
||||
this.currentScaleValue = newValue; |
||||
if (newScale === this.currentScale) { |
||||
return; |
||||
} |
||||
for (var i = 0, ii = this.pages.length; i < ii; i++) { |
||||
this.pages[i].update(newScale); |
||||
} |
||||
this.currentScale = newScale; |
||||
|
||||
if (!noScroll) { |
||||
var page = this.currentPageNumber, dest; |
||||
if (this.location && !this.inPresentationMode && |
||||
!IGNORE_CURRENT_POSITION_ON_ZOOM) { |
||||
page = this.location.pageNumber; |
||||
dest = [null, { name: 'XYZ' }, this.location.left, |
||||
this.location.top, null]; |
||||
} |
||||
this.pages[page - 1].scrollIntoView(dest); |
||||
} |
||||
|
||||
var event = document.createEvent('UIEvents'); |
||||
event.initUIEvent('scalechange', true, true, window, 0); |
||||
event.scale = newScale; |
||||
event.resetAutoSettings = resetAutoSettings; |
||||
if (preset) { |
||||
event.presetValue = newValue; |
||||
} |
||||
this.container.dispatchEvent(event); |
||||
}, |
||||
|
||||
setScale: function pdfViewer_setScale(value, resetAutoSettings, noScroll) { |
||||
if (value === 'custom') { |
||||
return; |
||||
} |
||||
var scale = parseFloat(value); |
||||
|
||||
if (scale > 0) { |
||||
this._setScaleUpdatePages(scale, value, true, noScroll, false); |
||||
} else { |
||||
var currentPage = this.pages[this.currentPageNumber - 1]; |
||||
if (!currentPage) { |
||||
return; |
||||
} |
||||
var hPadding = PresentationMode.active ? 0 : SCROLLBAR_PADDING; |
||||
var vPadding = PresentationMode.active ? 0 : VERTICAL_PADDING; |
||||
var pageWidthScale = (this.container.clientWidth - hPadding) / |
||||
currentPage.width * currentPage.scale; |
||||
var pageHeightScale = (this.container.clientHeight - vPadding) / |
||||
currentPage.height * currentPage.scale; |
||||
switch (value) { |
||||
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': |
||||
var isLandscape = (currentPage.width > currentPage.height); |
||||
var horizontalScale = isLandscape ? pageHeightScale : |
||||
pageWidthScale; |
||||
scale = Math.min(MAX_AUTO_SCALE, horizontalScale); |
||||
break; |
||||
default: |
||||
console.error('pdfViewSetScale: \'' + value + |
||||
'\' is an unknown zoom value.'); |
||||
return; |
||||
} |
||||
this._setScaleUpdatePages(scale, value, resetAutoSettings, noScroll, |
||||
true); |
||||
} |
||||
}, |
||||
|
||||
updateRotation: function pdfViewRotatePages(rotation) { |
||||
for (var i = 0, l = this.pages.length; i < l; i++) { |
||||
var page = this.pages[i]; |
||||
page.update(page.scale, rotation); |
||||
} |
||||
|
||||
this.setScale(this.currentScaleValue, true, true); |
||||
}, |
||||
|
||||
removeAllPages: function () { |
||||
var container = this.viewer; |
||||
while (container.hasChildNodes()) { |
||||
container.removeChild(container.lastChild); |
||||
} |
||||
this.pages = []; |
||||
}, |
||||
|
||||
updateLocation: function (firstPage) { |
||||
var currentScale = this.currentScale; |
||||
var currentScaleValue = this.currentScaleValue; |
||||
var normalizedScaleValue = |
||||
parseFloat(currentScaleValue) === currentScale ? |
||||
Math.round(currentScale * 10000) / 100 : currentScaleValue; |
||||
|
||||
var pageNumber = firstPage.id; |
||||
var pdfOpenParams = '#page=' + pageNumber; |
||||
pdfOpenParams += '&zoom=' + normalizedScaleValue; |
||||
var currentPageView = this.pages[pageNumber - 1]; |
||||
var container = this.container; |
||||
var topLeft = currentPageView.getPagePoint( |
||||
(container.scrollLeft - firstPage.x), |
||||
(container.scrollTop - firstPage.y)); |
||||
var intLeft = Math.round(topLeft[0]); |
||||
var intTop = Math.round(topLeft[1]); |
||||
pdfOpenParams += ',' + intLeft + ',' + intTop; |
||||
|
||||
this.location = { |
||||
pageNumber: pageNumber, |
||||
scale: normalizedScaleValue, |
||||
top: intTop, |
||||
left: intLeft, |
||||
pdfOpenParams: pdfOpenParams |
||||
}; |
||||
}, |
||||
|
||||
get inPresentationMode() { |
||||
return PresentationMode.active || PresentationMode.switchInProgress; |
||||
}, |
||||
|
||||
update: function () { |
||||
var visible = this.getVisiblePages(); |
||||
var visiblePages = visible.views; |
||||
if (visiblePages.length === 0) { |
||||
return; |
||||
} |
||||
|
||||
this.updateInProgress = true; |
||||
|
||||
var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, |
||||
2 * visiblePages.length + 1); |
||||
this.cache.resize(suggestedCacheSize); |
||||
|
||||
this.renderingQueue.renderHighestPriority(visible); |
||||
|
||||
var currentId = this.currentPageNumber; |
||||
var firstPage = visible.first; |
||||
|
||||
for (var i = 0, ii = visiblePages.length, stillFullyVisible = false; |
||||
i < ii; ++i) { |
||||
var page = visiblePages[i]; |
||||
|
||||
if (page.percent < 100) { |
||||
break; |
||||
} |
||||
if (page.id === this.currentPageNumber) { |
||||
stillFullyVisible = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!stillFullyVisible) { |
||||
currentId = visiblePages[0].id; |
||||
} |
||||
|
||||
if (!PresentationMode.active) { |
||||
this.setCurrentPageNumber(currentId); |
||||
} |
||||
|
||||
this.updateLocation(firstPage); |
||||
|
||||
this.updateInProgress = false; |
||||
|
||||
var event = document.createEvent('UIEvents'); |
||||
event.initUIEvent('updateviewarea', true, true, window, 0); |
||||
this.container.dispatchEvent(event); |
||||
}, |
||||
|
||||
containsElement: function (element) { |
||||
return this.container.contains(element); |
||||
}, |
||||
|
||||
focus: function () { |
||||
this.container.focus(); |
||||
}, |
||||
|
||||
blur: function () { |
||||
this.container.blur(); |
||||
}, |
||||
|
||||
get isHorizontalScrollbarEnabled() { |
||||
return (PresentationMode.active ? false : |
||||
(this.container.scrollWidth > this.container.clientWidth)); |
||||
}, |
||||
|
||||
getVisiblePages: function () { |
||||
if (!PresentationMode.active) { |
||||
return getVisibleElements(this.container, this.pages, true); |
||||
} else { |
||||
// The algorithm in getVisibleElements doesn't work in all browsers and
|
||||
// configurations when presentation mode is active.
|
||||
var visible = []; |
||||
var currentPage = this.pages[this.currentPageNumber - 1]; |
||||
visible.push({ id: currentPage.id, view: currentPage }); |
||||
return { first: currentPage, last: currentPage, views: visible }; |
||||
} |
||||
}, |
||||
|
||||
cleanup: function () { |
||||
for (var i = 0, ii = this.pages.length; i < ii; i++) { |
||||
if (this.pages[i] && |
||||
this.pages[i].renderingState !== RenderingStates.FINISHED) { |
||||
this.pages[i].reset(); |
||||
} |
||||
} |
||||
}, |
||||
|
||||
forceRendering: function (currentlyVisiblePages) { |
||||
var visiblePages = currentlyVisiblePages || this.getVisiblePages(); |
||||
var pageView = this.renderingQueue.getHighestPriority(visiblePages, |
||||
this.pages, |
||||
this.scroll.down); |
||||
if (pageView) { |
||||
this.renderingQueue.renderView(pageView, 'page'); |
||||
return; |
||||
} |
||||
}, |
||||
}; |
||||
|
||||
return PDFViewer; |
||||
})(); |
Loading…
Reference in new issue