| Index: chrome/browser/resources/print_preview/previewarea/preview_area.js
|
| diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chrome/browser/resources/print_preview/previewarea/preview_area.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4e76ee2a8a086c326d2baddb1abf42ab83065938
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js
|
| @@ -0,0 +1,464 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +cr.define('print_preview', function() {
|
| + 'use strict';
|
| +
|
| + /**
|
| + * Creates a PreviewArea object. It represents the area where the preview
|
| + * document is displayed.
|
| + *
|
| + * @param {print_preview.PrintTicketStore!} printTicketStore Used to get
|
| + * information about how the preview should be displayed.
|
| + * @param {print_preview.PreviewGenerator!} previewGenerator Used to read
|
| + * generated page previews.
|
| + * @constructor
|
| + * @extends {print_preview.Component}
|
| + */
|
| + function PreviewArea(printTicketStore, previewGenerator) {
|
| + print_preview.Component.call(this);
|
| +
|
| + /**
|
| + * Used to get information about how the preview should be displayed.
|
| + * @type {print_preview.PrintTicketStore!}
|
| + * @private
|
| + */
|
| + this.printTicketStore_ = printTicketStore;
|
| +
|
| + /**
|
| + * Used to read generated page previews.
|
| + * @type {print_preview.PreviewGenerator?}
|
| + * @private
|
| + */
|
| + this.previewGenerator_ = null;
|
| +
|
| + /**
|
| + * The embedded pdf plugin object. It's value is null if not yet loaded.
|
| + * @type {HTMLEmbedElement?}
|
| + * @private
|
| + */
|
| + this.plugin_ = null;
|
| +
|
| + /**
|
| + * Current zoom level as a percentage.
|
| + * @type {number}
|
| + * @private
|
| + */
|
| + this.zoomLevel_ = null;
|
| +
|
| + /**
|
| + * Current page offset which can be used to calculate scroll amount.
|
| + * @type {Object.<{x: number, y: number}>!}
|
| + * @private
|
| + */
|
| + this.pageOffset_ = {x: 0, y: 0};
|
| +
|
| + /**
|
| + * A rectangle describing the postion of the most visible page normalized
|
| + * with respect to the total height and width of the plugin.
|
| + * @type {print_preview.Rect}
|
| + * @private
|
| + */
|
| + this.pageLocationNormalized_ = null;
|
| + };
|
| +
|
| + /**
|
| + * Enumeration of events dispatched by the preview area.
|
| + * @enum {string}
|
| + */
|
| + PreviewArea.Event = {
|
| + OPEN_SYSTEM_DIALOG_CLICK:
|
| + 'print_preview.PreviewArea.OPEN_SYSTEM_DIALOG_CLICK',
|
| + PREVIEW_GENERATION_FAIL: 'print_preview.PreviewArea.PREVIEW_GENERATION_FAIL'
|
| + };
|
| +
|
| + /**
|
| + * CSS classes used by the preview area.
|
| + * @enum {string}
|
| + * @private
|
| + */
|
| + PreviewArea.Classes_ = {
|
| + COMPATIBILITY_OBJECT: 'preview-area-compatibility-object',
|
| + LOADING_MESSAGE: 'preview-area-loading-message',
|
| + NO_PLUGIN_MESSAGE: 'preview-area-no-plugin',
|
| + OPEN_SYSTEM_DIALOG_BUTTON: 'preview-area-open-system-dialog-button',
|
| + OPEN_SYSTEM_DIALOG_BUTTON_THROBBER:
|
| + 'preview-area-open-system-dialog-button-throbber',
|
| + OVERLAY: 'preview-area-overlay-layer',
|
| + PDF_PLUGIN: 'preview-area-pdf-plugin',
|
| + PREVIEW_FAILED_MESSAGE: 'preview-failed-message'
|
| + };
|
| +
|
| + PreviewArea.prototype = {
|
| + __proto__: print_preview.Component.prototype,
|
| +
|
| + /**
|
| + * Should only be called after calling this.render().
|
| + * @return {boolean} Whether the preview area has a compatible plugin to
|
| + * display the print preview in.
|
| + */
|
| + get hasCompatiblePlugin() {
|
| + return this.previewGenerator_ != null;
|
| + },
|
| +
|
| + handleDirectionalKeyEvent: function(e) {
|
| + // Make sure the PDF plugin is there.
|
| + if (!this.plugin_) {
|
| + return;
|
| + }
|
| +
|
| + // We only care about: PageUp, PageDown, Left, Up, Right, Down.
|
| + if (!arrayContains([33, 34, 37, 38, 39, 40], e.keyCode)) {
|
| + return;
|
| + }
|
| +
|
| + // If the user is holding a modifier key, ignore.
|
| + if (e.metaKey || e.altKey || e.shiftKey || e.ctrlKey) {
|
| + return;
|
| + }
|
| +
|
| + // Don't handle the key event for these elements.
|
| + var tagName = document.activeElement.tagName;
|
| + if (arrayContains(['INPUT', 'SELECT', 'EMBED'], tagName)) {
|
| + return;
|
| + }
|
| +
|
| + // For the most part, if any div of header was the last clicked element,
|
| + // then the active element is the body. Starting with the last clicked
|
| + // element, and work up the DOM tree to see if any element has a
|
| + // scrollbar. If there exists a scrollbar, do not handle the key event
|
| + // here.
|
| + var element = document.activeElement;
|
| + if (element == document.body) {
|
| + if (lastClickedElement)
|
| + element = lastClickedElement;
|
| + while (element) {
|
| + if (element.scrollHeight > element.clientHeight)
|
| + return;
|
| + element = element.parentElement;
|
| + }
|
| + }
|
| +
|
| + // No scroll bar anywhere, or the active element is something else, like a
|
| + // button. Note: buttons have a bigger scrollHeight than clientHeight.
|
| + this.plugin_.sendKeyEvent(e.keyCode);
|
| + e.preventDefault();
|
| + },
|
| +
|
| + /** @override */
|
| + enterDocument: function() {
|
| + print_preview.Component.prototype.enterDocument.call(this);
|
| + this.tracker.add(
|
| + this.openSystemDialogButton_,
|
| + 'click',
|
| + this.onOpenSystemDialogButtonClick_.bind(this));
|
| +
|
| + this.tracker.add(
|
| + this.printTicketStore_,
|
| + print_preview.PrintTicketStore.Event.INITIALIZE,
|
| + this.onTicketInitialize_.bind(this));
|
| + this.tracker.add(
|
| + this.printTicketStore_,
|
| + print_preview.PrintTicketStore.Event.TICKET_CHANGE,
|
| + this.onTicketChange_.bind(this));
|
| + this.tracker.add(
|
| + this.printTicketStore_,
|
| + print_preview.PrintTicketStore.Event.CAPABILITIES_CHANGE,
|
| + this.onTicketChange_.bind(this));
|
| + this.tracker.add(
|
| + this.printTicketStore_,
|
| + print_preview.PrintTicketStore.Event.DOCUMENT_CHANGE,
|
| + this.onDocumentChange_.bind(this));
|
| +
|
| + if (this.checkPluginCompatibility_()) {
|
| + this.previewGenerator_ = new print_preview.PreviewGenerator(
|
| + this.printTicketStore_);
|
| + this.tracker.add(
|
| + this.previewGenerator_,
|
| + print_preview.PreviewGenerator.Event.PAGE_READY,
|
| + this.onPagePreviewReady_.bind(this));
|
| + this.tracker.add(
|
| + this.previewGenerator_,
|
| + print_preview.PreviewGenerator.Event.DOCUMENT_READY,
|
| + this.onDocumentPreviewReady_.bind(this));
|
| + this.tracker.add(
|
| + this.previewGenerator_,
|
| + print_preview.PreviewGenerator.Event.FAIL,
|
| + this.onPreviewGenerationFail_.bind(this));
|
| + } else {
|
| + // Hide loading message and show no plugin message.
|
| + this.hideLoadingMessage_();
|
| + var noPluginMessage = this.getElement().getElementsByClassName(
|
| + PreviewArea.Classes_.NO_PLUGIN_MESSAGE)[0];
|
| + setIsVisible(noPluginMessage, true);;
|
| + }
|
| + },
|
| +
|
| + get overlayEl_() {
|
| + return this.getElement().getElementsByClassName(
|
| + PreviewArea.Classes_.OVERLAY)[0];
|
| + },
|
| +
|
| + get openSystemDialogButton_() {
|
| + return this.getElement().getElementsByClassName(
|
| + PreviewArea.Classes_.OPEN_SYSTEM_DIALOG_BUTTON)[0];
|
| + },
|
| +
|
| + /**
|
| + * Checks to see if a suitable plugin for rendering the preview exists. If
|
| + * one does not exist, then an error message will be displayed.
|
| + * @return {boolean} Whether Chromium has a suitable plugin for rendering
|
| + * the preview.
|
| + * @private
|
| + */
|
| + checkPluginCompatibility_: function() {
|
| + var compatObj = this.getElement().getElementsByClassName(
|
| + PreviewArea.Classes_.COMPATIBILITY_OBJECT)[0];
|
| + var isCompatible =
|
| + compatObj.onload &&
|
| + compatObj.goToPage &&
|
| + compatObj.removePrintButton &&
|
| + compatObj.loadPreviewPage &&
|
| + compatObj.printPreviewPageCount &&
|
| + compatObj.resetPrintPreviewUrl &&
|
| + compatObj.onPluginSizeChanged &&
|
| + compatObj.onScroll &&
|
| + compatObj.pageXOffset &&
|
| + compatObj.pageYOffset &&
|
| + compatObj.setZoomLevel &&
|
| + compatObj.setPageNumbers &&
|
| + compatObj.setPageXOffset &&
|
| + compatObj.setPageYOffset &&
|
| + compatObj.getHorizontalScrollbarThickness &&
|
| + compatObj.getVerticalScrollbarThickness &&
|
| + compatObj.getPageLocationNormalized &&
|
| + compatObj.getHeight &&
|
| + compatObj.getWidth;
|
| + compatObj.parentElement.removeChild(compatObj);
|
| + return isCompatible;
|
| + },
|
| +
|
| + /**
|
| + * Hides the loading message.
|
| + * @private
|
| + */
|
| + hideLoadingMessage_: function() {
|
| + var loadingMessage = this.getElement().getElementsByClassName(
|
| + PreviewArea.Classes_.LOADING_MESSAGE)[0];
|
| + setIsVisible(loadingMessage, false);
|
| + },
|
| +
|
| + createPlugin_: function(srcUrl) {
|
| + if (this.plugin_) {
|
| + throw Error('Pdf preview plugin already created');
|
| + }
|
| + this.plugin_ = document.createElement('embed');
|
| + this.plugin_.setAttribute('class', 'preview-area-plugin');
|
| + this.plugin_.setAttribute(
|
| + 'type', 'application/x-google-chrome-print-preview-pdf');
|
| + this.plugin_.setAttribute('src', srcUrl);
|
| + this.plugin_.setAttribute('aria-live', 'polite');
|
| + this.plugin_.setAttribute('aria-atomic', 'true');
|
| + this.getElement().appendChild(this.plugin_);
|
| +
|
| + global['onPreviewPluginLoad'] = this.onPluginLoad_.bind(this);
|
| + this.plugin_.onload('onPreviewPluginLoad()');
|
| +
|
| + global['onPreviewPluginVisualStateChange'] =
|
| + this.onPreviewVisualStateChange_.bind(this);
|
| + this.plugin_.onScroll('onPreviewPluginVisualStateChange()');
|
| + this.plugin_.onPluginSizeChanged('onPreviewPluginVisualStateChange()');
|
| +
|
| + this.plugin_.removePrintButton();
|
| + this.plugin_.grayscale(!this.printTicketStore_.isColorEnabled());
|
| +
|
| + this.overlayEl_.classList.add('invisible');
|
| + this.hideLoadingMessage_();
|
| + },
|
| +
|
| + /**
|
| + * Called when the open-system-dialog button is clicked. Disables the
|
| + * button, shows the throbber, and dispatches the OPEN_SYSTEM_DIALOG_CLICK
|
| + * event.
|
| + * @private
|
| + */
|
| + onOpenSystemDialogButtonClick_: function() {
|
| + this.openSystemDialogButton_.disabled = true;
|
| + var openSystemDialogThrobber = this.getElement().getElementsByClassName(
|
| + PreviewArea.Classes_.OPEN_SYSTEM_DIALOG_BUTTON_THROBBER)[0];
|
| + setIsVisible(openSystemDialogThrobber, true);
|
| + cr.dispatchSimpleEvent(this, PreviewArea.Event.OPEN_SYSTEM_DIALOG_CLICK);
|
| + },
|
| +
|
| + onTicketInitialize_: function() {
|
| + if (this.previewGenerator_ && this.printTicketStore_.isTicketValid()) {
|
| + this.previewGenerator_.requestPreview();
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Called when the print ticket changes. Updates the preview.
|
| + * @private
|
| + */
|
| + onTicketChange_: function() {
|
| + if (this.previewGenerator_ && this.printTicketStore_.isTicketValid()) {
|
| + this.previewGenerator_.requestPreview();
|
| + }
|
| + },
|
| +
|
| + onDocumentChange_: function() {
|
| + if (this.plugin_) {
|
| + this.plugin_.printPreviewPageCount(
|
| + this.printTicketStore_.getPageNumberSet().size);
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Called when a page preview has been generated. Updates the plugin with
|
| + * the new page.
|
| + * @param {cr.Event} evt Contains information about the page preview.
|
| + * @private
|
| + */
|
| + onPagePreviewReady_: function(evt) {
|
| + if (!this.plugin_) {
|
| + this.createPlugin_(evt.previewUrl);
|
| + }
|
| + if (evt.previewIndex == 0) {
|
| + this.plugin_.goToPage('0');
|
| + this.plugin_.resetPrintPreviewUrl(evt.previewUrl);
|
| + this.plugin_.reload();
|
| + this.plugin_.grayscale(!this.printTicketStore_.isColorEnabled());
|
| + }
|
| + this.plugin_.loadPreviewPage(evt.previewUrl, evt.previewIndex);
|
| + // TODO May have to reposition the scroll.
|
| + },
|
| +
|
| + onDocumentPreviewReady_: function() {
|
| + // TODO Delete me?
|
| + },
|
| +
|
| + onPreviewGenerationFail_: function() {
|
| + this.overlayEl_.classList.remove('invisible');
|
| + var previewFailedMessage = this.getElement().getElementsByClassName(
|
| + PreviewArea.Classes_.PREVIEW_FAILED_MESSAGE)[0];
|
| + setIsVisible(previewFailedMessage, true);
|
| + cr.dispatchSimpleEvent(this, PreviewArea.Event.PREVIEW_GENERATION_FAIL);
|
| + },
|
| +
|
| + onPluginLoad_: function() {
|
| + // Setting the plugin's page count can only be called after the plugin is
|
| + // loaded.
|
| + this.plugin_.printPreviewPageCount(
|
| + this.printTicketStore_.getPageNumberSet().size);
|
| + this.plugin_.fitToHeight();
|
| + // TODO
|
| +// if (this.zoomLevel_ != null && this.pageOffset_ != null) {
|
| +// this.plugin_.setZoomLevel(this.zoomLevel_);
|
| +// this.plugin_.setPageXOffset(this.pageOffset_.x);
|
| +// this.plugin_.setPageYOffset(this.pageOffset_.y);
|
| +// } else {
|
| +// this.plugin_.fitToHeight();
|
| +// }
|
| + },
|
| +
|
| + onPreviewVisualStateChange_: function() {
|
| + log('print_preview.PreviewArea.onPreviewVisualStateChange_');
|
| + // TODO update margins UI since preview has moved.
|
| + },
|
| +
|
| + /**
|
| + * The width of the plugin area in pixels, excluding any visible scrollbars,
|
| + * @type {number}
|
| + */
|
| + get width() {
|
| + return this.widthPercent * this.plugin_.offsetWidth;
|
| + },
|
| +
|
| + /**
|
| + * The height of the plugin area in pixels, excluding any visible
|
| + * scrollbars.
|
| + * @type {number}
|
| + */
|
| + get height() {
|
| + return this.heightPercent * this.plugin_.offsetHeight;
|
| + },
|
| +
|
| + /**
|
| + * The width of the plugin area in percent, excluding any visible
|
| + * scrollbars.
|
| + * @type {number}
|
| + */
|
| + get widthPercent() {
|
| + var width = this.plugin_.getWidth();
|
| + var scrollbarWidth = this.plugin_.getVerticalScrollbarThickness();
|
| + return (width - scrollbarWidth) / width;
|
| + },
|
| +
|
| + /**
|
| + * The height of the plugin area in percent, excluding any visible
|
| + * scrollbars.
|
| + * @type {number}
|
| + */
|
| + get heightPercent() {
|
| + var height = this.plugin_.getHeight();
|
| + var scrollbarHeight = this.plugin_.getHorizontalScrollbarThickness();
|
| + return (height - scrollbarHeight) / height;
|
| + },
|
| +
|
| + /**
|
| + * Queries the plugin for the location of the most visible page and updates
|
| + * |this.pageLocationNormalized|.
|
| + */
|
| + update: function() {
|
| + if (!this.pdfLoaded_)
|
| + return;
|
| + var pluginLocation =
|
| + this.plugin_.getPageLocationNormalized().split(';');
|
| + this.pageLocationNormalized = new print_preview.Rect(
|
| + parseFloat(pluginLocation[0]),
|
| + parseFloat(pluginLocation[1]),
|
| + parseFloat(pluginLocation[2]),
|
| + parseFloat(pluginLocation[3]));
|
| + },
|
| +
|
| + /**
|
| + * Resets the state variables of |this|.
|
| + */
|
| + resetState: function() {
|
| + if (this.plugin_) {
|
| + this.zoomLevel_ = this.plugin_.getZoomLevel();
|
| + this.pageOffset_ = {
|
| + x: this.plugin_.pageXOffset(),
|
| + y: this.plugin_.pageYOffset()
|
| + };
|
| + }
|
| + this.pdfLoaded_ = false;
|
| + },
|
| +
|
| + /**
|
| + * Hides the |this.overlayLayer| and any messages currently displayed.
|
| + */
|
| + hideOverlayLayer: function() {
|
| + this.tracker.add(this.overlayLayer, 'webkitTransitionEnd',
|
| + this.hideOverlayLayerCleanup_.bind(this), false);
|
| + if (this.plugin_)
|
| + this.plugin_.classList.remove('invisible');
|
| + this.overlayLayer.classList.add('invisible');
|
| + },
|
| +
|
| + /**
|
| + * Necessary cleanup so that the dancing dots animation is not being
|
| + * rendered in the background when not displayed.
|
| + */
|
| + hideOverlayLayerCleanup_: function() {
|
| + this.customMessageWithDots_.hidden = true;
|
| + this.tracker.remove(this.overlayLayer, 'webkitTransitionEnd');
|
| + }
|
| + };
|
| +
|
| + // Export
|
| + return {
|
| + PreviewArea: PreviewArea
|
| + };
|
| +});
|
|
|