Commit 40b2aee1 authored by raymes@chromium.org's avatar raymes@chromium.org

Convert the code in pdf.js to an object

This is a refactoring of the code in pdf.js, moving the code into a PDFViewer object. This
will make it more testable and usable by other classes that will be added later.

BUG=303491

Review URL: https://codereview.chromium.org/223363002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@262917 0039d316-1c4b-4281-b951-d872f2087c98
parent f6eeeac1
...@@ -8,243 +8,267 @@ ...@@ -8,243 +8,267 @@
<include src="../../../../ui/webui/resources/js/util.js"></include> <include src="../../../../ui/webui/resources/js/util.js"></include>
<include src="viewport.js"></include> <include src="viewport.js"></include>
// The plugin element is sized to fill the entire window and is set to be fixed /**
// positioning, acting as a viewport. The plugin renders into this viewport * Creates a new PDFViewer. There should only be one of these objects per
// according to the scroll position of the window. * document.
var plugin; */
function PDFViewer() {
// The sizer element is placed behind the plugin element to cause scrollbars
// to be displayed in the window. It is sized according to the document size
// of the pdf and zoom level.
this.sizer_ = $('sizer');
this.toolbar_ = $('toolbar');
this.pageIndicator_ = $('page-indicator');
this.progressBar_ = $('progress-bar');
this.passwordScreen_ = $('password-screen');
this.passwordScreen_.addEventListener('password-submitted',
this.onPasswordSubmitted_.bind(this));
this.errorScreen_ = $('error-screen');
this.errorScreen_.text = 'Failed to load PDF document';
// This element is placed behind the plugin element to cause scrollbars to be // Create the viewport.
// displayed in the window. It is sized according to the document size of the this.viewport_ = new Viewport(window,
// pdf and zoom level. this.sizer_,
var sizer; this.isFitToPageEnabled_.bind(this),
this.viewportChangedCallback_.bind(this));
// The toolbar element. // Create the plugin object dynamically so we can set its src. The plugin
var viewerToolbar; // element is sized to fill the entire window and is set to be fixed
// positioning, acting as a viewport. The plugin renders into this viewport
// according to the scroll position of the window.
this.plugin_ = document.createElement('object');
this.plugin_.id = 'plugin';
this.plugin_.type = 'application/x-google-chrome-pdf';
this.plugin_.addEventListener('message', this.handleMessage_.bind(this),
false);
// The pdf location is passed in stream details in the background page.
var streamDetails = chrome.extension.getBackgroundPage().popStreamDetails();
this.plugin_.setAttribute('src', streamDetails.streamUrl);
document.body.appendChild(this.plugin_);
// The page indicator element. this.setupEventListeners_(streamDetails);
var viewerPageIndicator; }
// The progress bar element. PDFViewer.prototype = {
var viewerProgressBar; /**
* @private
* Sets up event listeners for key shortcuts and also the UI buttons.
* @param {Object} streamDetails the details of the original HTTP request for
* the PDF.
*/
setupEventListeners_: function(streamDetails) {
// Setup the button event listeners.
$('fit-to-width-button').addEventListener('click',
this.viewport_.fitToWidth.bind(this.viewport_));
$('fit-to-page-button').addEventListener('click',
this.viewport_.fitToPage.bind(this.viewport_));
$('zoom-in-button').addEventListener('click',
this.viewport_.zoomIn.bind(this.viewport_));
$('zoom-out-button').addEventListener('click',
this.viewport_.zoomOut.bind(this.viewport_));
$('save-button-link').href = streamDetails.originalUrl;
$('print-button').addEventListener('click', this.print_.bind(this));
// The element indicating there was an error loading the document. // Setup keyboard event listeners.
var viewerErrorScreen; document.onkeydown = function(e) {
switch (e.keyCode) {
case 37: // Left arrow key.
// Go to the previous page if there are no horizontal scrollbars.
if (!this.viewport_.documentHasScrollbars().x) {
this.viewport_.goToPage(this.viewport_.getMostVisiblePage() - 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 33: // Page up key.
// Go to the previous page if we are fit-to-page.
if (isFitToPageEnabled()) {
this.viewport_.goToPage(this.viewport_.getMostVisiblePage() - 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 39: // Right arrow key.
// Go to the next page if there are no horizontal scrollbars.
if (!this.viewport_.documentHasScrollbars().x) {
this.viewport_.goToPage(this.viewport_.getMostVisiblePage() + 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 34: // Page down key.
// Go to the next page if we are fit-to-page.
if (isFitToPageEnabled()) {
this.viewport_.goToPage(this.viewport_.getMostVisiblePage() + 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 187: // +/= key.
case 107: // Numpad + key.
if (e.ctrlKey || e.metaKey) {
this.viewport_.zoomIn();
// Since we do the zooming of the page.
e.preventDefault();
}
return;
case 189: // -/_ key.
case 109: // Numpad - key.
if (e.ctrlKey || e.metaKey) {
this.viewport_.zoomOut();
// Since we do the zooming of the page.
e.preventDefault();
}
return;
case 83: // s key.
if (e.ctrlKey || e.metaKey) {
// Simulate a click on the button so that the <a download ...>
// attribute is used.
$('save-button-link').click();
// Since we do the saving of the page.
e.preventDefault();
}
return;
case 80: // p key.
if (e.ctrlKey || e.metaKey) {
this.print_();
// Since we do the printing of the page.
e.preventDefault();
}
return;
}
}.bind(this);
},
// The viewport object.
var viewport;
// The element displaying the password screen. /**
var viewerPasswordScreen; * @private
* Notify the plugin to print.
*/
print_: function() {
this.plugin_.postMessage({
type: 'print',
});
},
// The document dimensions. /**
var documentDimensions; * @private
* @return {boolean} true if the fit-to-page button is enabled.
*/
isFitToPageEnabled_: function() {
return $('fit-to-page-button').classList.contains('polymer-selected');
},
// Notify the plugin to print. /**
function print() { * @private
plugin.postMessage({ * Update the loading progress of the document in response to a progress
type: 'print', * message being received from the plugin.
}); * @param {number} progress the progress as a percentage.
} */
updateProgress_: function(progress) {
this.progressBar_.progress = progress;
if (progress == -1) {
// Document load failed.
this.errorScreen_.style.visibility = 'visible';
this.sizer_.style.display = 'none';
this.toolbar_.style.visibility = 'hidden';
if (this.passwordScreen_.active) {
this.passwordScreen_.deny();
this.passwordScreen_.active = false;
}
}
},
// Returns true if the fit-to-page button is enabled. /**
function isFitToPageEnabled() { * @private
return $('fit-to-page-button').classList.contains('polymer-selected'); * An event handler for handling password-submitted events. These are fired
} * when an event is entered into the password screen.
* @param {Object} event a password-submitted event.
*/
onPasswordSubmitted_: function(event) {
this.plugin_.postMessage({
type: 'getPasswordComplete',
password: event.detail.password
});
},
function updateProgress(progress) { /**
viewerProgressBar.progress = progress; * @private
if (progress == -1) { * An event handler for handling message events received from the plugin.
// Document load failed. * @param {MessageObject} message a message event.
viewerErrorScreen.style.visibility = 'visible'; */
sizer.style.display = 'none'; handleMessage_: function(message) {
viewerToolbar.style.visibility = 'hidden'; switch (message.data.type.toString()) {
if (viewerPasswordScreen.active) { case 'documentDimensions':
viewerPasswordScreen.deny(); this.documentDimensions_ = message.data;
viewerPasswordScreen.active = false; this.viewport_.setDocumentDimensions(this.documentDimensions_);
} this.toolbar_.style.visibility = 'visible';
} // If we received the document dimensions, the password was good so we
} // can dismiss the password screen.
if (this.passwordScreen_.active)
this.passwordScreen_.accept();
function onPasswordSubmitted(event) { this.pageIndicator_.initialFadeIn();
plugin.postMessage({ this.toolbar_.initialFadeIn();
type: 'getPasswordComplete', break;
password: event.detail.password case 'loadProgress':
}); this.updateProgress_(message.data.progress);
} break;
case 'goToPage':
this.viewport_.goToPage(message.data.page);
break;
case 'getPassword':
// If the password screen isn't up, put it up. Otherwise we're
// responding to an incorrect password so deny it.
if (!this.passwordScreen_.active)
this.passwordScreen_.active = true;
else
this.passwordScreen_.deny();
}
},
// Called when a message is received from the plugin. /**
function handleMessage(message) { * @private
switch (message.data.type.toString()) { * A callback that's called when the viewport changes.
case 'documentDimensions': * @param {number} zoom the zoom level.
documentDimensions = message.data; * @param {number} x the x scroll coordinate.
viewport.setDocumentDimensions(documentDimensions); * @param {number} y the y scroll coordinate.
viewerToolbar.style.visibility = 'visible'; * @param {number} scrollbarWidth the width of scrollbars on the page.
// If we received the document dimensions, the password was good so we can * @param {Object} hasScrollbars whether the viewport has a
// dismiss the password screen. * horizontal/vertical scrollbar.
if (viewerPasswordScreen.active) * @param {number} page the index of the most visible page in the viewport.
viewerPasswordScreen.accept(); */
viewportChangedCallback_: function(zoom,
viewerPageIndicator.initialFadeIn(); x,
viewerToolbar.initialFadeIn(); y,
break; scrollbarWidth,
case 'loadProgress': hasScrollbars,
updateProgress(message.data.progress); page) {
break; // Offset the toolbar position so that it doesn't move if scrollbars appear.
case 'goToPage': var toolbarRight = hasScrollbars.y ? 0 : scrollbarWidth;
viewport.goToPage(message.data.page); var toolbarBottom = hasScrollbars.x ? 0 : scrollbarWidth;
break; this.toolbar_.style.right = toolbarRight + 'px';
case 'getPassword': this.toolbar_.style.bottom = toolbarBottom + 'px';
// If the password screen isn't up, put it up. Otherwise we're responding
// to an incorrect password so deny it.
if (!viewerPasswordScreen.active)
viewerPasswordScreen.active = true;
else
viewerPasswordScreen.deny();
}
}
// Callback that's called when the viewport changes. // Show or hide the page indicator.
function viewportChangedCallback(zoom, if (this.documentDimensions_.pageDimensions.length > 1 && hasScrollbars.y)
x, this.pageIndicator_.style.visibility = 'visible';
y, else
scrollbarWidth, this.pageIndicator_.style.visibility = 'hidden';
hasScrollbars,
page) {
// Offset the toolbar position so that it doesn't move if scrollbars appear.
var toolbarRight = hasScrollbars.y ? 0 : scrollbarWidth;
var toolbarBottom = hasScrollbars.x ? 0 : scrollbarWidth;
viewerToolbar.style.right = toolbarRight + 'px';
viewerToolbar.style.bottom = toolbarBottom + 'px';
// Show or hide the page indicator.
if (documentDimensions.pageDimensions.length > 1 && hasScrollbars.y)
viewerPageIndicator.style.visibility = 'visible';
else
viewerPageIndicator.style.visibility = 'hidden';
// Update the most visible page.
viewerPageIndicator.text = page + 1;
// Notify the plugin of the viewport change.
plugin.postMessage({
type: 'viewport',
zoom: zoom,
xOffset: x,
yOffset: y
});
}
function load() { // Update the most visible page.
sizer = $('sizer'); this.pageIndicator_.text = page + 1;
viewerToolbar = $('toolbar');
viewerPageIndicator = $('page-indicator');
viewerProgressBar = $('progress-bar');
viewerPasswordScreen = $('password-screen');
viewerPasswordScreen.addEventListener('password-submitted',
onPasswordSubmitted);
viewerErrorScreen = $('error-screen');
viewerErrorScreen.text = 'Failed to load PDF document';
// Create the viewport. // Notify the plugin of the viewport change.
viewport = new Viewport(window, this.plugin_.postMessage({
sizer, type: 'viewport',
isFitToPageEnabled, zoom: zoom,
viewportChangedCallback); xOffset: x,
yOffset: y
// Create the plugin object dynamically so we can set its src. });
plugin = document.createElement('object'); },
plugin.id = 'plugin';
plugin.type = 'application/x-google-chrome-pdf';
plugin.addEventListener('message', handleMessage, false);
// The pdf location is passed in stream details in the background page.
var streamDetails = chrome.extension.getBackgroundPage().popStreamDetails();
plugin.setAttribute('src', streamDetails.streamUrl);
document.body.appendChild(plugin);
// Setup the button event listeners.
$('fit-to-width-button').addEventListener('click',
viewport.fitToWidth.bind(viewport));
$('fit-to-page-button').addEventListener('click',
viewport.fitToPage.bind(viewport));
$('zoom-in-button').addEventListener('click',
viewport.zoomIn.bind(viewport));
$('zoom-out-button').addEventListener('click',
viewport.zoomOut.bind(viewport));
$('save-button-link').href = streamDetails.originalUrl;
$('print-button').addEventListener('click', print);
// Setup keyboard event listeners.
document.onkeydown = function(e) {
switch (e.keyCode) {
case 37: // Left arrow key.
// Go to the previous page if there are no horizontal scrollbars.
if (!viewport.documentHasScrollbars().x) {
viewport.goToPage(viewport.getMostVisiblePage() - 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 33: // Page up key.
// Go to the previous page if we are fit-to-page.
if (isFitToPageEnabled()) {
viewport.goToPage(viewport.getMostVisiblePage() - 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 39: // Right arrow key.
// Go to the next page if there are no horizontal scrollbars.
if (!viewport.documentHasScrollbars().x) {
viewport.goToPage(viewport.getMostVisiblePage() + 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 34: // Page down key.
// Go to the next page if we are fit-to-page.
if (isFitToPageEnabled()) {
viewport.goToPage(viewport.getMostVisiblePage() + 1);
// Since we do the movement of the page.
e.preventDefault();
}
return;
case 187: // +/= key.
case 107: // Numpad + key.
if (e.ctrlKey || e.metaKey) {
viewport.zoomIn();
// Since we do the zooming of the page.
e.preventDefault();
}
return;
case 189: // -/_ key.
case 109: // Numpad - key.
if (e.ctrlKey || e.metaKey) {
viewport.zoomOut();
// Since we do the zooming of the page.
e.preventDefault();
}
return;
case 83: // s key.
if (e.ctrlKey || e.metaKey) {
// Simulate a click on the button so that the <a download ...>
// attribute is used.
$('save-button-link').click();
// Since we do the saving of the page.
e.preventDefault();
}
return;
case 80: // p key.
if (e.ctrlKey || e.metaKey) {
print();
// Since we do the printing of the page.
e.preventDefault();
}
return;
}
};
} }
load(); new PDFViewer();
})(); })();
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment