summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/print_preview
diff options
context:
space:
mode:
authordpapad@chromium.org <dpapad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-12 08:57:22 +0000
committerdpapad@chromium.org <dpapad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-12 08:57:22 +0000
commit05b14b552fa44d27b7f0d12c19f9a39064c85868 (patch)
tree85079247735df754a321f3da6dee7ced3fdb181f /chrome/browser/resources/print_preview
parentb691a100e6ff4aec4880a6957d6a79921ac53eda (diff)
downloadchromium_src-05b14b552fa44d27b7f0d12c19f9a39064c85868.zip
chromium_src-05b14b552fa44d27b7f0d12c19f9a39064c85868.tar.gz
chromium_src-05b14b552fa44d27b7f0d12c19f9a39064c85868.tar.bz2
Print Preview: Adding UI for margin settings.
BUG=69337 TEST=Open print preview. Margin options should be available. Review URL: http://codereview.chromium.org/7891016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105044 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/resources/print_preview')
-rw-r--r--chrome/browser/resources/print_preview/margin_line.js181
-rw-r--r--chrome/browser/resources/print_preview/margin_settings.js450
-rw-r--r--chrome/browser/resources/print_preview/margin_textbox.js282
-rw-r--r--chrome/browser/resources/print_preview/margin_utils.js87
-rw-r--r--chrome/browser/resources/print_preview/margins_ui.js136
-rw-r--r--chrome/browser/resources/print_preview/preview_area.js136
-rw-r--r--chrome/browser/resources/print_preview/print_header.js5
-rw-r--r--chrome/browser/resources/print_preview/print_preview.css39
-rw-r--r--chrome/browser/resources/print_preview/print_preview.html6
-rw-r--r--chrome/browser/resources/print_preview/print_preview.js85
-rw-r--r--chrome/browser/resources/print_preview/print_preview_utils.js21
-rw-r--r--chrome/browser/resources/print_preview/print_preview_utils_test.html12
12 files changed, 1370 insertions, 70 deletions
diff --git a/chrome/browser/resources/print_preview/margin_line.js b/chrome/browser/resources/print_preview/margin_line.js
new file mode 100644
index 0000000..f8999c1
--- /dev/null
+++ b/chrome/browser/resources/print_preview/margin_line.js
@@ -0,0 +1,181 @@
+// Copyright (c) 2011 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() {
+ 'strict';
+
+ function MarginLine(groupName) {
+ var line = document.createElement('div');
+ line.__proto__ = MarginLine.prototype;
+ line.className = MarginLine.CSS_CLASS_DRAGGABLE_AREA;
+ // @type {string} Specifies which margin this line refers to.
+ line.marginGroup = groupName;
+ // @type {print_preview.Rect} A rectangle describing the values of all
+ // margins.
+ line.rectangle = null;
+ // @type {HTMLDivElement} The dotted line representing the margin.
+ line.visibleLine = document.createElement('div');
+ line.visibleLine.className = MarginLine.CSS_CLASS_MARGIN_LINE;
+
+ line.appendChild(line.visibleLine);
+ return line;
+ }
+
+ MarginLine.CSS_CLASS_MARGIN_LINE = 'margin-line';
+ MarginLine.CSS_CLASS_DRAGGABLE_AREA = 'draggable-area';
+ // Width of the clickable region around each margin line in screen pixels.
+ MarginLine.CLICKABLE_REGION = 20;
+
+ MarginLine.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ update: function(marginsRectangle) {
+ this.rectangle = this.getCoordinates_(marginsRectangle);
+ },
+
+ /**
+ * Draws |this| on screen. Essentially two divs are being drawn, the drag
+ * control area (invisible) and the dotted margin line (visible).
+ */
+ draw: function() {
+ this.drawDraggableArea_();
+ this.drawDottedLine_();
+ },
+
+ /**
+ * Draws the dotted line representing the margin.
+ * @private
+ */
+ drawDottedLine_ : function() {
+ var rectangle = this.getVisibleLineCoordinates_();
+ this.visibleLine.style.left = 100 * rectangle.x + '%';
+ this.visibleLine.style.top = 100 * rectangle.y + '%';
+ this.visibleLine.style.width = 100 * rectangle.width + '%';
+ this.visibleLine.style.height = 100 * rectangle.height + '%';
+ },
+
+ /**
+ * Draws the area the draggable area (not visible).
+ * @private
+ */
+ drawDraggableArea_: function() {
+ var width = previewArea.pdfPlugin_.offsetWidth;
+ var height = previewArea.pdfPlugin_.offsetHeight;
+
+ this.style.left = Math.round(this.rectangle.x * width) + 'px';
+ this.style.top = Math.round(this.rectangle.y * height) + 'px';
+ this.style.width = Math.round(this.rectangle.width * width) + 'px';
+ this.style.height = Math.round(this.rectangle.height * height) + 'px';
+ },
+
+ /**
+ * Calculates the coordinates and size of |this|.
+ * @param {print_preview.Rect} marginsRectangle A rectangle describing the
+ * selected margins values in percentages.
+ * @private
+ */
+ getCoordinates_: function(marginsRectangle) {
+ var pageLocation = previewArea.getPageLocationNormalized();
+ var totalWidth = previewArea.pdfPlugin_.offsetWidth;
+ var totalHeight = previewArea.pdfPlugin_.offsetHeight;
+ var offsetY = (MarginLine.CLICKABLE_REGION / 2) / totalHeight;
+ var offsetX = (MarginLine.CLICKABLE_REGION / 2) / totalWidth;
+
+ if (this.isTop_()) {
+ var lineCoordinates = new print_preview.Rect(
+ pageLocation.x,
+ marginsRectangle.y - offsetY,
+ pageLocation.width,
+ MarginLine.CLICKABLE_REGION / totalHeight);
+ } else if (this.isBottom_()) {
+ var lineCoordinates = new print_preview.Rect(
+ pageLocation.x,
+ marginsRectangle.bottom - offsetY,
+ pageLocation.width,
+ MarginLine.CLICKABLE_REGION / totalHeight);
+ } else if (this.isRight_()) {
+ var lineCoordinates = new print_preview.Rect(
+ marginsRectangle.right - offsetX,
+ pageLocation.y,
+ MarginLine.CLICKABLE_REGION / totalWidth,
+ pageLocation.height);
+ } else if (this.isLeft_()) {
+ var lineCoordinates = new print_preview.Rect(
+ marginsRectangle.x - offsetX,
+ pageLocation.y,
+ MarginLine.CLICKABLE_REGION / totalWidth,
+ pageLocation.height);
+ }
+ return lineCoordinates;
+ },
+
+ /**
+ * Calculates the coordinates in percentages and size of the visible margin
+ * line, with respect to |this| div element.
+ * @return {print_preview.Rect} A rectangle describing the position of the
+ * visible line in percentages.
+ * @private
+ */
+ getVisibleLineCoordinates_: function() {
+ if (this.isHorizontal_())
+ var innerMarginsRect = new print_preview.Rect(0, 0.5, 1, 0);
+ else if (this.isVertical_())
+ var innerMarginsRect = new print_preview.Rect(0.5, 0, 0, 1);
+ return innerMarginsRect;
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the top margin.
+ * @private
+ */
+ isTop_: function() {
+ return this.marginGroup == print_preview.MarginSettings.TOP_GROUP;
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the bottom margin.
+ * @private
+ */
+ isBottom_: function() {
+ return this.marginGroup == print_preview.MarginSettings.BOTTOM_GROUP;
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the left margin.
+ * @private
+ */
+ isLeft_: function() {
+ return this.marginGroup == print_preview.MarginSettings.LEFT_GROUP;
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the bottom margin.
+ * @private
+ */
+ isRight_: function() {
+ return this.marginGroup == print_preview.MarginSettings.RIGHT_GROUP;
+ },
+
+ /**
+ * @return {boolean} True if |this| is a horizontal line.
+ * @private
+ */
+ isHorizontal_: function() {
+ return this.isTop_() || this.isBottom_() ;
+ },
+
+ /**
+ * @return {boolean} True if |this| is a vertical line.
+ * @private
+ */
+ isVertical_: function() {
+ return this.isLeft_() || this.isRight_();
+ },
+
+ };
+
+ return {
+ MarginLine: MarginLine
+ };
+});
diff --git a/chrome/browser/resources/print_preview/margin_settings.js b/chrome/browser/resources/print_preview/margin_settings.js
index f9d81a3..5f48ed7 100644
--- a/chrome/browser/resources/print_preview/margin_settings.js
+++ b/chrome/browser/resources/print_preview/margin_settings.js
@@ -6,6 +6,107 @@ cr.define('print_preview', function() {
'use strict';
/**
+ * Creates a Margins object that holds four margin values. The units in which
+ * the values are expressed can be any numeric value.
+ * @constructor
+ * @param {number} left The left margin.
+ * @param {number} top The top margin.
+ * @param {number} right The right margin.
+ * @param {number} bottom The bottom margin.
+ */
+ function Margins(left, top, right, bottom) {
+ this[MarginSettings.LEFT_GROUP] = left;
+ this[MarginSettings.TOP_GROUP] = top;
+ this[MarginSettings.RIGHT_GROUP] = right;
+ this[MarginSettings.BOTTOM_GROUP] = bottom;
+ }
+
+ /**
+ * Rounds |value| keeping |precision| decimal numbers. Example: 32.76643
+ * becomes 32.77.
+ * @param {number} value The number to round.
+ * @param {number} precision The desired precision.
+ * @return {number} The rounded number.
+ */
+ Margins.roundToPrecision = function(value, precision) {
+ return Math.round(value * Math.pow(10, precision)) /
+ Math.pow(10, precision);
+ }
+
+ Margins.prototype = {
+ /**
+ * Checks if |rhs| is equal to |this|.
+ * @param {Margins} rhs The Margins object to compare against.
+ * @return {boolean} true if they are equal.
+ */
+ isEqual: function(rhs) {
+ return this[MarginSettings.TOP_GROUP] === rhs[MarginSettings.TOP_GROUP] &&
+ this[MarginSettings.LEFT_GROUP] === rhs[MarginSettings.LEFT_GROUP] &&
+ this[MarginSettings.RIGHT_GROUP] ===
+ rhs[MarginSettings.RIGHT_GROUP] &&
+ this[MarginSettings.BOTTOM_GROUP] ===
+ rhs[MarginSettings.BOTTOM_GROUP];
+ },
+
+ /**
+ * Copies the four margin values from |rhs|.
+ * @param {Margins} rhs The Margins object values to be used.
+ */
+ copy: function(rhs) {
+ this[MarginSettings.TOP_GROUP] = rhs[MarginSettings.TOP_GROUP];
+ this[MarginSettings.LEFT_GROUP] = rhs[MarginSettings.LEFT_GROUP];
+ this[MarginSettings.RIGHT_GROUP] = rhs[MarginSettings.RIGHT_GROUP];
+ this[MarginSettings.BOTTOM_GROUP] = rhs[MarginSettings.BOTTOM_GROUP];
+ },
+
+ /**
+ * Converts |this| to inches and returns the result in a new Margins object.
+ * |this| is not affected. It assumes that |this| is currently expressed in
+ * points.
+ * @param {number} The number of decimal points to keep.
+ * @return {Margins} The equivalent of |this| in inches.
+ */
+ toInches: function(precision) {
+ return new Margins(
+ Margins.roundToPrecision(convertPointsToInches(
+ this[MarginSettings.LEFT_GROUP]), precision),
+ Margins.roundToPrecision(convertPointsToInches(
+ this[MarginSettings.TOP_GROUP]), precision),
+ Margins.roundToPrecision(convertPointsToInches(
+ this[MarginSettings.RIGHT_GROUP]), precision),
+ Margins.roundToPrecision(convertPointsToInches(
+ this[MarginSettings.BOTTOM_GROUP]), precision)
+ );
+ }
+ };
+
+ /**
+ * @constructor
+ * Class describing the layout of the page.
+ */
+ function PageLayout(width, height, left, top, right, bottom) {
+ this.contentWidth_ = width;
+ this.contentHeight_ = height;
+ this.margins_ = new Margins(left, top, right, bottom);
+ }
+
+ PageLayout.prototype = {
+ /**
+ * @type {number} The width of the page.
+ */
+ get pageWidth() {
+ return this.margins_.left + this.margins_.right + this.contentWidth_;
+ },
+
+ /**
+ * @type {number} The height of the page.
+ */
+ get pageHeight() {
+ return this.margins_.top + this.margins_.bottom + this.contentHeight_;
+ }
+ };
+
+ /**
* Creates a MarginSettings object. This object encapsulates all settings and
* logic related to the margins mode.
* @constructor
@@ -13,65 +114,130 @@ cr.define('print_preview', function() {
function MarginSettings() {
this.marginsOption_ = $('margins-option');
this.marginList_ = $('margin-list');
- // Holds the custom left margin value (if set).
- this.customMarginLeft_ = -1;
- // Holds the custom right margin value (if set).
- this.customMarginRight_ = -1;
- // Holds the custom top margin value (if set).
- this.customMarginTop_ = -1;
- // Holds the custom bottom margin value (if set).
- this.customMarginBottom_ = -1;
- // Margin list values.
- this.customMarginsValue_ = 2;
- this.defaultMarginsValue_ = 0;
- this.noMarginsValue_ = 1;
- // Default Margins option index.
- this.defaultMarginsIndex_ = 0;
+ this.marginsUI_ = null;
+
+ // Holds the custom margin values in points (if set).
+ this.customMargins_ = new Margins(-1, -1, -1, -1);
+ // Holds the previous custom margin values in points.
+ this.previousCustomMargins_ = new Margins(-1, -1, -1, -1);
+ // Holds the width of the page in points.
+ this.pageWidth_ = -1;
+ // Holds the height of the page in points.
+ this.pageHeight_ = -1;
+ // The last selected margin option.
+ this.lastSelectedOption_ = MarginSettings.MARGINS_VALUE_DEFAULT;
+
+ // Holds the currently updated default page layout values.
+ this.currentDefaultPageLayout = null;
+ // Holds the default page layout values when the custom margins was last
+ // selected.
+ this.previousDefaultPageLayout_ = null;
+
+ // True if the margins UI should be shown regardless of mouse position.
+ this.forceDisplayingMarginLines_ = true;
}
+ // Number of points per inch.
+ MarginSettings.POINTS_PER_INCH = 72;
+ // Margin list values.
+ MarginSettings.MARGINS_VALUE_DEFAULT = 0;
+ MarginSettings.MARGINS_VALUE_NO_MARGINS = 1;
+ MarginSettings.MARGINS_VALUE_CUSTOM = 2;
+ // Default Margins option index.
+ MarginSettings.DEFAULT_MARGINS_OPTION_INDEX = 0;
+ // Group name corresponding to the top margin.
+ MarginSettings.TOP_GROUP = 'top';
+ // Group name corresponding to the left margin.
+ MarginSettings.LEFT_GROUP = 'left';
+ // Group name corresponding to the right margin.
+ MarginSettings.RIGHT_GROUP = 'right';
+ // Group name corresponding to the bottom margin.
+ MarginSettings.BOTTOM_GROUP = 'bottom';
+
cr.addSingletonGetter(MarginSettings);
MarginSettings.prototype = {
/**
- * The selection list corresponding to the margins option.
- * @return {HTMLInputElement}
- */
- get marginList() {
- return this.marginList_;
- },
-
- /**
* Returns a dictionary of the four custom margin values.
* @return {object}
*/
get customMargins() {
- return {'marginLeft': this.customMarginLeft_,
- 'marginTop': this.customMarginTop_,
- 'marginRight': this.customMarginRight_,
- 'marginBottom': this.customMarginBottom_};
+ var margins = {};
+ margins.marginLeft = this.customMargins_.left;
+ margins.marginTop = this.customMargins_.top;
+ margins.marginRight = this.customMargins_.right;
+ margins.marginBottom = this.customMargins_.bottom;
+ return margins;
},
/**
- * Gets the value of the selected margin option.
+ * @return {number} The value of the selected margin option.
* @private
- * @return {number}
*/
get selectedMarginsValue_() {
return this.marginList_.options[this.marginList_.selectedIndex].value;
},
/**
- * Checks whether user has selected the Default Margins option or not.
- *
- * @return {boolean} true if default margins are selected.
+ * @return {boolean} True if default margins are selected.
*/
isDefaultMarginsSelected: function() {
- return this.selectedMarginsValue_ == this.defaultMarginsValue_;
+ return this.selectedMarginsValue_ == MarginSettings.MARGINS_VALUE_DEFAULT;
},
/**
- * Adds listeners to all margin related controls. The listeners take care
- * of altering their behavior depending on |hasPendingPreviewRequest|.
+ * @return {boolean} True if no margins are selected.
+ */
+ isNoMarginsSelected: function() {
+ return this.selectedMarginsValue_ ==
+ MarginSettings.MARGINS_VALUE_NO_MARGINS;
+ },
+
+ /**
+ * @return {boolean} True if custom margins are selected.
+ */
+ isCustomMarginsSelected: function() {
+ return this.selectedMarginsValue_ == MarginSettings.MARGINS_VALUE_CUSTOM;
+ },
+
+ /**
+ * If the custom margin values have changed then request a new preview based
+ * on the newly set margins.
+ * @private
+ */
+ requestPreviewIfNeeded_: function() {
+ if (!this.areMarginSettingsValid())
+ return;
+ if (this.customMargins_.toInches(2).isEqual(
+ this.previousCustomMargins_.toInches(2))) {
+ return;
+ }
+ this.previousCustomMargins_.copy(this.customMargins_);
+ setDefaultValuesAndRegeneratePreview(false);
+ },
+
+ /**
+ * Listener executed when the mouse is over the sidebar. If the custom
+ * margin lines are displayed, then, it fades them out.
+ * @private
+ */
+ onSidebarMouseOver_: function(e) {
+ if (!this.forceDisplayingMarginLines_)
+ this.marginsUI.hide();
+ },
+
+ /**
+ * Listener executed when the mouse is over the main view. If the custom
+ * margin lines are hidden, then, it fades them in.
+ * @private
+ */
+ onMainviewMouseOver_: function() {
+ this.forceDisplayingMarginLines_ = false;
+ this.marginsUI.show();
+ },
+
+ /**
+ * Adds listeners to all margin related controls.
*/
addEventListeners: function() {
this.marginList_.onchange = this.onMarginsChanged_.bind(this);
@@ -79,34 +245,221 @@ cr.define('print_preview', function() {
},
/**
- * Listener executing when user selects a different margin option, ie,
- * |this.marginList_| is changed.
+ * @return {boolean} True if the margin settings are valid.
+ */
+ areMarginSettingsValid: function() {
+ if (this.marginsUI_ == null)
+ return true;
+
+ var pairs = this.marginsUI.pairsAsList;
+ return pairs.every(function(pair) { return pair.box_.isValid; });
+ },
+
+ /**
+ * Calculates the maximum allowable value of the selected margin text for
+ * every margin.
+ * @return {array} The maximum allowable value in order top, left, right,
+ * bottom.
+ * @private
+ */
+ getMarginValueLimits_: function() {
+ var marginValueLimits = [];
+ marginValueLimits[0] = this.pageHeight_ - this.customMargins_.bottom;
+ marginValueLimits[1] = this.pageWidth_ - this.customMargins_.right;
+ marginValueLimits[2] = this.pageWidth_ - this.customMargins_.left;
+ marginValueLimits[3] = this.pageHeight_ - this.customMargins_.top;
+ return marginValueLimits;
+ },
+
+ /**
+ * When the user stops typing in the margin text box a new print preview is
+ * requested, only if
+ * 1) The input is compeletely valid (it can be parsed in its entirety).
+ * 2) The newly selected margins differ from the previously selected.
+ * @param {cr.Event} event The change event holding information about what
+ * changed.
+ * @private
+ */
+ onMarginTextValueMayHaveChanged_: function(event) {
+ var marginBox = event.target;
+ var marginBoxValue = convertInchesToPoints(marginBox.margin);
+ this.customMargins_[marginBox.marginGroup] = marginBoxValue;
+ this.requestPreviewIfNeeded_();
+ },
+
+ /**
+ * @type {print_preview.MarginsUI} The object holding the UI for specifying
+ * custom margins.
+ */
+ get marginsUI() {
+ if (!this.marginsUI_) {
+ this.marginsUI_ = new print_preview.MarginsUI($('mainview'));
+ this.marginsUI_.addObserver(
+ this.onMarginTextValueMayHaveChanged_.bind(this));
+ }
+ return this.marginsUI_;
+ },
+
+ /**
+ * Adds listeners when the custom margins option is selected.
+ * @private
+ */
+ addCustomMarginEventListeners_: function() {
+ $('mainview').onmouseover = this.onMainviewMouseOver_.bind(this);
+ $('sidebar').onmouseover = this.onSidebarMouseOver_.bind(this);
+ },
+
+ /**
+ * Removes the event listeners associated with the custom margins option.
+ * @private
+ */
+ removeCustomMarginEventListeners_: function() {
+ $('mainview').onmouseover = null;
+ $('sidebar').onmouseover = null;
+ this.marginsUI.hide();
+ },
+
+ /**
+ * Updates |this.marginsUI| depending on the specified margins and the
+ * position of the page within the plugin.
+ * @private
+ */
+ drawCustomMarginsUI_: function() {
+ // TODO(dpapad): find out why passing |!this.areMarginsSettingsValid()|
+ // directly produces the opposite value even though
+ // |this.getMarginsRectangleInPercent_()| and
+ // |this.getMarginValueLimits_()| have no side effects.
+ var keepDisplayedValue = !this.areMarginSettingsValid();
+ this.marginsUI.update(this.getMarginsRectangleInPercent_(),
+ this.customMargins_,
+ this.getMarginValueLimits_(),
+ keepDisplayedValue);
+ this.marginsUI.draw();
+ },
+
+ /**
+ * Called when there is change in the preview position or size.
+ */
+ onPreviewPositionChanged: function() {
+ if (this.isCustomMarginsSelected() && previewArea.pdfLoaded &&
+ pageSettings.totalPageCount != undefined) {
+ this.drawCustomMarginsUI_();
+ }
+ },
+
+ /**
+ * Executes when user selects a different margin option, ie,
+ * |this.marginList_.selectedIndex| is changed.
* @private
*/
onMarginsChanged_: function() {
- if (this.selectedMarginsValue_ == this.defaultMarginsValue_) {
- setDefaultValuesAndRegeneratePreview(false);
- } else if (this.selectedMarginsValue_ == this.noMarginsValue_) {
- this.customMarginLeft_ = 0;
- this.customMarginTop_ = 0;
- this.customMarginRight_ = 0;
- this.customMarginBottom_ = 0;
- setDefaultValuesAndRegeneratePreview(false);
+ if (this.isDefaultMarginsSelected())
+ this.onDefaultMarginsSelected_();
+ else if (this.isNoMarginsSelected())
+ this.onNoMarginsSelected_();
+ else if (this.isCustomMarginsSelected())
+ this.onCustomMarginsSelected_();
+
+ this.lastSelectedOption_ = this.selectedMarginsValue_;
+ },
+
+ /**
+ * Executes when the default margins option is selected.
+ * @private
+ */
+ onDefaultMarginsSelected_: function() {
+ this.removeCustomMarginEventListeners_();
+ this.forceDisplayingMarginLines_ = true;
+ setDefaultValuesAndRegeneratePreview(false);
+ },
+
+ /**
+ * Executes when the no margins option is selected.
+ * @private
+ */
+ onNoMarginsSelected_: function() {
+ this.removeCustomMarginEventListeners_();
+ this.forceDisplayingMarginLines_ = true;
+ this.customMargins_ = new Margins(0, 0, 0, 0);
+ setDefaultValuesAndRegeneratePreview(false);
+ },
+
+ /**
+ * Executes when the custom margins option is selected.
+ * @private
+ */
+ onCustomMarginsSelected_: function() {
+ this.addCustomMarginEventListeners_();
+
+ if (this.lastSelectedOption_ == MarginSettings.MARGINS_VALUE_DEFAULT)
+ this.customMargins_ = this.currentDefaultPageLayout.margins_;
+ this.previousCustomMargins_.copy(this.customMargins_);
+
+ if (this.previousDefaultPageLayout_ != this.currentDefaultPageLayout) {
+ this.pageWidth_ = this.currentDefaultPageLayout.pageWidth;
+ this.pageHeight_ = this.currentDefaultPageLayout.pageHeight;
}
- // TODO(aayushkumar): Add handler for custom margins
+
+ this.previousDefaultPageLayout_ = this.currentDefaultPageLayout;
+ this.drawCustomMarginsUI_();
+ this.marginsUI.show();
+ },
+
+ /**
+ * Calculates the coordinates of the four margin lines. These are the
+ * coordinates where the margin lines should be displayed. The coordinates
+ * are expressed in terms of percentages with respect to the total width
+ * and height of the plugin.
+ * @return {print_preview.Rect} A rectnangle that describes the position of
+ * the four margin lines.
+ * @private
+ */
+ getMarginsRectangleInPercent_: function() {
+ var pageLocation = previewArea.getPageLocationNormalized();
+ var marginsInPercent = this.getMarginsInPercent_();
+ var leftX = pageLocation.x + marginsInPercent.left;
+ var topY = pageLocation.y + marginsInPercent.top;
+ var contentWidth = pageLocation.width - (marginsInPercent.left +
+ marginsInPercent.right);
+ var contentHeight = pageLocation.height - (marginsInPercent.top +
+ marginsInPercent.bottom);
+ return new print_preview.Rect(
+ leftX, topY, contentWidth, contentHeight);
+ },
+
+ /**
+ * @return {print_preview.Margins} The currently selected margin values
+ * normalized to the total width and height of the plugin.
+ * @private
+ */
+ getMarginsInPercent_: function() {
+ var pageInformation = previewArea.getPageLocationNormalized();
+ var totalWidthInPoints = this.pageWidth_ / pageInformation.width;
+ var totalHeightInPoints = this.pageHeight_ / pageInformation.height;
+ var marginsInPercent = new Margins(
+ this.customMargins_.left / totalWidthInPoints,
+ this.customMargins_.top / totalHeightInPoints,
+ this.customMargins_.right / totalWidthInPoints,
+ this.customMargins_.bottom / totalHeightInPoints);
+ return marginsInPercent;
},
/**
* If custom margins is the currently selected option then change to the
* default margins option.
+ * @private
*/
resetMarginsIfNeeded: function() {
- if (this.selectedMarginsValue_ == this.customMarginsValue_)
- this.marginList_.options[this.defaultMarginsIndex_].selected = true;
+ if (this.isCustomMarginsSelected()) {
+ this.marginList_.options[
+ MarginSettings.DEFAULT_MARGINS_OPTION_INDEX].selected = true;
+ this.removeCustomMarginEventListeners_();
+ this.lastSelectedOption_ = MarginSettings.MARGINS_VALUE_DEFAULT;
+ }
},
/**
- * Listener executing when a PDFLoaded event occurs.
+ * Executes when a PDFLoaded event occurs.
* @private
*/
onPDFLoaded_: function() {
@@ -117,5 +470,6 @@ cr.define('print_preview', function() {
return {
MarginSettings: MarginSettings,
+ PageLayout: PageLayout,
};
});
diff --git a/chrome/browser/resources/print_preview/margin_textbox.js b/chrome/browser/resources/print_preview/margin_textbox.js
new file mode 100644
index 0000000..5034bbf
--- /dev/null
+++ b/chrome/browser/resources/print_preview/margin_textbox.js
@@ -0,0 +1,282 @@
+// Copyright (c) 2011 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() {
+ 'strict';
+
+ function MarginTextbox(groupName) {
+ var box = document.createElement('input');
+ box.__proto__ = MarginTextbox.prototype;
+ box.setAttribute('type', 'text');
+ box.className = MarginTextbox.CSS_CLASS_MARGIN_TEXTBOX;
+ box.value = '0';
+
+ // @type {string} Specifies which margin this line refers to.
+ box.marginGroup = groupName;
+ // @type {boolean} True if the displayed value is valid.
+ box.isValid = true;
+ // @type {number} Timer used to detect when the user stops typing.
+ box.timerId_ = null;
+ // @type {number} The last valid value in points.
+ box.lastValidValueInPoints = 0;
+ // @type {print_preview.Rect} A rectangle describing the four margins.
+ box.marginsRectangle_ = null;
+ // @type {number} The upper allowed limit for the corresponding margin.
+ box.valueLimit = null;
+
+ box.addEventListeners_();
+ return box;
+ }
+
+ MarginTextbox.CSS_CLASS_MARGIN_TEXTBOX = 'margin-box';
+ MarginTextbox.MARGIN_BOX_HEIGHT = 15;
+ MarginTextbox.MARGIN_BOX_VERTICAL_PADDING = 5;
+ MarginTextbox.MARGIN_BOX_WIDTH = 40;
+ MarginTextbox.MARGIN_BOX_HORIZONTAL_PADDING = 10;
+
+ // Keycode for the "Escape" key.
+ MarginTextbox.ESCAPE_KEYCODE = 27;
+ // Keycode for the "Enter" key.
+ MarginTextbox.ENTER_KEYCODE = 13;
+
+ MarginTextbox.convertPointsToInchesText = function(toConvert) {
+ var inInches = convertPointsToInches(toConvert);
+ return MarginTextbox.convertInchesToInchesText(inInches);
+ };
+
+ MarginTextbox.convertInchesToInchesText = function(toConvert) {
+ return toConvert.toFixed(2) + '"';
+ };
+
+ /**
+ * @return {number} The total height of a margin textbox (including padding).
+ */
+ MarginTextbox.totalHeight = function() {
+ return MarginTextbox.MARGIN_BOX_HEIGHT +
+ 2 * MarginTextbox.MARGIN_BOX_VERTICAL_PADDING;
+ }
+
+ /**
+ * @return {number} The total width of a margin textbox (including padding).
+ */
+ MarginTextbox.totalWidth = function() {
+ return MarginTextbox.MARGIN_BOX_WIDTH +
+ 2 * MarginTextbox.MARGIN_BOX_HORIZONTAL_PADDING;
+ }
+
+ MarginTextbox.prototype = {
+ __proto__: HTMLInputElement.prototype,
+
+ /**
+ * Updates the state of |this|.
+ * @param {print_preview.Rect} marginsRectangle A rectangle describing the
+ * margins in percentages.
+ * @param {number} value The margin value in points.
+ * @param {number} valueLimit The upper allowed value for the margin.
+ * @param {boolean} keepDisplayedValue True if the currently displayed value
+ * should not be updated.
+ */
+ update: function(marginsRectangle, value, valueLimit, keepDisplayedValue) {
+ this.marginsRectangle_ = marginsRectangle;
+ this.lastValidValueInPoints = value;
+ if (!keepDisplayedValue) {
+ this.value = MarginTextbox.convertPointsToInchesText(
+ this.lastValidValueInPoints);
+ }
+
+ this.valueLimit = valueLimit;
+ this.validate();
+ },
+
+ get margin() {
+ return print_preview.extractMarginValue(this.value);
+ },
+
+ /**
+ * Updates |this.isValid|.
+ */
+ validate: function() {
+ this.isValid = print_preview.isMarginTextValid(this.value,
+ this.valueLimit);
+ if (this.isValid)
+ this.value = MarginTextbox.convertInchesToInchesText(this.margin);
+ },
+
+ /**
+ * Updates the background color depending on |isValid| by adding/removing
+ * the appropriate CSS class.
+ * @param {boolean} isValid True if the margin is valid.
+ */
+ updateColor: function() {
+ this.isValid ? this.classList.remove('invalid') :
+ this.classList.add('invalid');
+ },
+
+ /**
+ * Draws this textbox.
+ */
+ draw: function() {
+ var topLeft = this.getCoordinates_();
+ var totalWidth = previewArea.pdfPlugin_.offsetWidth;
+ var totalHeight = previewArea.pdfPlugin_.offsetHeight;
+
+ this.style.left = Math.round(topLeft.x * totalWidth) + 'px';
+ this.style.top = Math.round(topLeft.y * totalHeight) + 'px';
+ this.updateColor();
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the top margin.
+ * @private
+ */
+ isTop_: function() {
+ return this.marginGroup == print_preview.MarginSettings.TOP_GROUP;
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the bottom margin.
+ * @private
+ */
+ isBottom_: function() {
+ return this.marginGroup == print_preview.MarginSettings.BOTTOM_GROUP;
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the left margin.
+ * @private
+ */
+ isLeft_: function() {
+ return this.marginGroup == print_preview.MarginSettings.LEFT_GROUP;
+ },
+
+ /**
+ * @return {boolean} True if |this| refers to the bottom margin.
+ * @private
+ */
+ isRight_: function() {
+ return this.marginGroup == print_preview.MarginSettings.RIGHT_GROUP;
+ },
+
+ /**
+ * Calculates the coordinates where |this| should be displayed.
+ * @return {{x: number, y: number}} The coordinates (in percent) where
+ * |this| should be drawn relative to the upper left corner of the
+ * plugin.
+ * @private
+ */
+ getCoordinates_: function() {
+ var x = 0, y = 0;
+ var totalWidth = previewArea.pdfPlugin_.offsetWidth;
+ var totalHeight = previewArea.pdfPlugin_.offsetHeight;
+ var offsetY = (MarginTextbox.totalHeight() / 2) / totalHeight;
+ var offsetX = (MarginTextbox.totalWidth() / 2) / totalWidth;
+
+ if (this.isTop_()) {
+ x = this.marginsRectangle_.middleX - offsetX;
+ y = this.marginsRectangle_.y;
+ } else if (this.isBottom_()) {
+ x = this.marginsRectangle_.middleX - offsetX;
+ y = this.marginsRectangle_.bottom - 2 * offsetY;
+ } else if (this.isRight_()) {
+ x = this.marginsRectangle_.right - 2 * offsetX;
+ y = this.marginsRectangle_.middleY - offsetY;
+ } else if (this.isLeft_()) {
+ x = this.marginsRectangle_.x;
+ y = this.marginsRectangle_.middleY - offsetY;
+ }
+
+ return { x: x, y: y };
+ },
+
+ /**
+ * Adds event listeners for various events.
+ * @private
+ */
+ addEventListeners_: function() {
+ this.oninput = this.resetTimer_.bind(this);
+ this.onblur = this.onBlur_.bind(this);
+ this.onkeypress = this.onKeyPressed_.bind(this);
+ this.onkeyup = this.onKeyUp_.bind(this);
+ },
+
+ /**
+ * Executes whenever a blur event occurs.
+ * @private
+ */
+ onBlur_: function() {
+ clearTimeout(this.timerId_);
+ this.validate();
+ if (!this.isValid) {
+ this.value = MarginTextbox.convertPointsToInchesText(
+ this.lastValidValueInPoints);
+ this.validate();
+ }
+
+ this.updateColor();
+ cr.dispatchSimpleEvent(document, 'updateSummary');
+ cr.dispatchSimpleEvent(document, 'updatePrintButton');
+ cr.dispatchSimpleEvent(this, 'MarginsMayHaveChanged');
+ },
+
+ /**
+ * Executes whenever a keypressed event occurs. Note: Only the "Enter" key
+ * event is handled. The "Escape" key does not result in such event,
+ * therefore it is handled by |this.onKeyUp_|.
+ * @param {KeyboardEvent} e The event that triggered this listener.
+ * @private
+ */
+ onKeyPressed_: function(e) {
+ if (e.keyCode == MarginTextbox.ENTER_KEYCODE)
+ this.blur();
+ },
+
+ /**
+ * Executes whenever a keyup event occurs. Note: Only the "Escape"
+ * key event is handled.
+ * @param {KeyboardEvent} e The event that triggered this listener.
+ * @private
+ */
+ onKeyUp_: function(e) {
+ if (e.keyCode == MarginTextbox.ESCAPE_KEYCODE) {
+ this.value = MarginTextbox.convertPointsToInchesText(
+ this.lastValidValueInPoints);
+ this.validate();
+ this.updateColor();
+ cr.dispatchSimpleEvent(document, 'updateSummary');
+ cr.dispatchSimpleEvent(document, 'updatePrintButton');
+ }
+ },
+
+ /**
+ * Resetting the timer used to detect when the user stops typing in order
+ * to update the print preview.
+ * @private
+ */
+ resetTimer_: function() {
+ clearTimeout(this.timerId_);
+ this.timerId_ = window.setTimeout(
+ this.onTextValueMayHaveChanged_.bind(this), 500);
+ },
+
+ /**
+ * Executes whenever the user stops typing.
+ * @private
+ */
+ onTextValueMayHaveChanged_: function() {
+ this.validate();
+ this.updateColor();
+ cr.dispatchSimpleEvent(document, 'updateSummary');
+ cr.dispatchSimpleEvent(document, 'updatePrintButton');
+
+ if (!this.isValid)
+ return;
+ cr.dispatchSimpleEvent(this, 'MarginsMayHaveChanged');
+ }
+
+ };
+
+ return {
+ MarginTextbox: MarginTextbox
+ };
+});
diff --git a/chrome/browser/resources/print_preview/margin_utils.js b/chrome/browser/resources/print_preview/margin_utils.js
new file mode 100644
index 0000000..73a925a
--- /dev/null
+++ b/chrome/browser/resources/print_preview/margin_utils.js
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 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';
+
+ /**
+ * Checks if |text| has a valid margin value format. A valid format is
+ * parsable as a number and is greater than zero.
+ * Example: "1.00", "1", ".5", "1.1" are valid values.
+ * Example: "1.4dsf", "-1" are invalid.
+ * Note: The inch symbol (") at the end of |text| is allowed.
+ *
+ * @param {string} text The text to check.
+ * @return {number} The margin value represented by |text| or null if |text|
+ * does not represent a valid number.
+ */
+ function extractMarginValue(text) {
+ // Remove whitespace anywhere in the string.
+ text.replace(/\s*/g, '');
+ if (text.length == 0)
+ return -1;
+ // Remove the inch(") symbol at end of string if present.
+ if (text.charAt(text.length - 1) == '\"')
+ text = text.slice(0, text.length - 1);
+ var regex = /^\d*(\.\d+)?$/
+ if (regex.test(text))
+ return parseFloat(text);
+ return -1;
+ }
+
+ /**
+ * @param {sting} text The text to check (in inches).
+ * @param {number} limit The upper bound of the valid margin range (in
+ * points).
+ * @return {boolean} True of |text| can be parsed and it is within the allowed
+ * range.
+ */
+ function isMarginTextValid(text, limit) {
+ var value = extractMarginValue(text);
+ if (value == -1)
+ return false;
+ value = convertInchesToPoints(value);
+ return value <= limit;
+ }
+
+ /**
+ * Creates a Rect object. This object describes a rectangle in a 2D plane. The
+ * units of |x|, |y|, |width|, |height| are chosen by clients of this class.
+ * @constructor
+ */
+ function Rect(x, y, width, height) {
+ // @type {number} Horizontal distance of the upper left corner from origin.
+ this.x = x;
+ // @type {number} Vertical distance of the upper left corner from origin.
+ this.y = y;
+ // @type {number} Width of |this| rectangle.
+ this.width = width;
+ // @type {number} Height of |this| rectangle.
+ this.height = height;
+ };
+
+ Rect.prototype = {
+ get right() {
+ return this.x + this.width;
+ },
+
+ get bottom() {
+ return this.y + this.height;
+ },
+
+ get middleX() {
+ return this.x + this.width / 2;
+ },
+
+ get middleY() {
+ return this.y + this.height / 2;
+ }
+ };
+
+ return {
+ extractMarginValue: extractMarginValue,
+ isMarginTextValid: isMarginTextValid,
+ Rect: Rect,
+ };
+});
diff --git a/chrome/browser/resources/print_preview/margins_ui.js b/chrome/browser/resources/print_preview/margins_ui.js
new file mode 100644
index 0000000..443f8fd
--- /dev/null
+++ b/chrome/browser/resources/print_preview/margins_ui.js
@@ -0,0 +1,136 @@
+// Copyright (c) 2011 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() {
+ 'strict';
+
+ /**
+ * @constructor
+ * This class represents a margin line and a textbox corresponding to that
+ * margin.
+ */
+ function MarginsUIPair(groupName) {
+ this.line_ = new print_preview.MarginLine(groupName);
+ this.box_ = new print_preview.MarginTextbox(groupName);
+ }
+
+ MarginsUIPair.prototype = {
+ __proto__: MarginsUIPair.prototype,
+
+ /**
+ * Updates the state.
+ */
+ update: function(marginsRectangle, value, valueLimit, keepDisplayedValue) {
+ this.line_.update(marginsRectangle);
+ this.box_.update(marginsRectangle, value, valueLimit, keepDisplayedValue);
+ },
+
+ /**
+ * Draws |this| based on the state.
+ */
+ draw: function() {
+ this.line_.draw();
+ this.box_.draw();
+ }
+ };
+
+ function MarginsUI(parentNode) {
+ var marginsUI = document.createElement('div');
+ marginsUI.__proto__ = MarginsUI.prototype;
+ marginsUI.id = 'customized-margins';
+
+ marginsUI.topPair_ = new MarginsUIPair(
+ print_preview.MarginSettings.TOP_GROUP);
+ marginsUI.leftPair_ = new MarginsUIPair(
+ print_preview.MarginSettings.LEFT_GROUP);
+ marginsUI.rightPair_ = new MarginsUIPair(
+ print_preview.MarginSettings.RIGHT_GROUP);
+ marginsUI.bottomPair_ = new MarginsUIPair(
+ print_preview.MarginSettings.BOTTOM_GROUP);
+ parentNode.appendChild(marginsUI);
+
+ var uiPairs = marginsUI.pairsAsList;
+ for (var i = 0; i < uiPairs.length; i++) {
+ marginsUI.appendChild(uiPairs[i].line_);
+ marginsUI.appendChild(uiPairs[i].box_);
+ }
+ return marginsUI;
+ }
+
+ MarginsUI.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ /**
+ * Adds an observer for |MarginsMayHaveChanged| event.
+ * @param {function} func A callback function to be called when
+ * |MarginsMayHaveChanged| event occurs.
+ */
+ addObserver: function(func) {
+ var uiPairs = this.pairsAsList;
+ for (var i = 0; i < uiPairs.length; i++)
+ uiPairs[i].box_.addEventListener('MarginsMayHaveChanged', func);
+ },
+
+ /**
+ * @return {array} An array including all |MarginUIPair| objects.
+ */
+ get pairsAsList() {
+ return [this.topPair_, this.leftPair_, this.rightPair_, this.bottomPair_];
+ },
+
+ /**
+ * Updates the state of the margins UI.
+ * @param {print_preview.Rect}
+ * @param {Margins} marginValues
+ * @param {array} valueLimits
+ */
+ update: function(marginsRectangle, marginValues, valueLimits,
+ keepDisplayedValue) {
+ var uiPairs = this.pairsAsList;
+ var order = ['top', 'left', 'right', 'bottom'];
+ for (var i = 0; i < uiPairs.length; i++) {
+ uiPairs[i].update(marginsRectangle,
+ marginValues[order[i]],
+ valueLimits[i],
+ keepDisplayedValue);
+ }
+ },
+
+ /**
+ * Draws |this| based on the latest state.
+ */
+ draw: function() {
+ this.applyClippingMask_();
+ this.pairsAsList.forEach(function(pair) { pair.draw(); });
+ },
+
+ /**
+ * Shows the margins UI.
+ */
+ show: function() {
+ this.hidden = false;
+ },
+
+ /**
+ * Hides the margins UI.
+ */
+ hide: function() {
+ this.hidden = true;
+ },
+
+ /**
+ * Applies a clipping mask on |this| so that it does not paint on top of the
+ * scrollbars (if any).
+ */
+ applyClippingMask_: function() {
+ var bottom = previewArea.height;
+ var right = previewArea.width;
+ this.style.clip = "rect(0, " + right + "px, " + bottom + "px, 0)";
+ }
+ };
+
+ return {
+ MarginsUI: MarginsUI
+ };
+});
diff --git a/chrome/browser/resources/print_preview/preview_area.js b/chrome/browser/resources/print_preview/preview_area.js
new file mode 100644
index 0000000..8a970a2
--- /dev/null
+++ b/chrome/browser/resources/print_preview/preview_area.js
@@ -0,0 +1,136 @@
+// Copyright (c) 2011 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() {
+ 'strict';
+
+ /**
+ * Creates a PreviewArea object. It represents the area where the preview
+ * document is displayed.
+ * @constructor
+ */
+ function PreviewArea() {
+ // The embedded pdf plugin object.
+ this.pdfPlugin_ = null;
+
+ // True if the pdf document is loaded in the preview area.
+ this.pdfLoaded_ = false;
+
+ // Contains the zoom level just before a new preview is requested so the
+ // same zoom level can be restored.
+ this.zoomLevel_ = null;
+ // @type {{x: number, y: number}} Contains the page offset values just
+ // before a new preview is requested so that the scroll amount can be
+ // restored later.
+ this.pageOffset_ = null;
+ }
+
+ cr.addSingletonGetter(PreviewArea);
+
+ PreviewArea.prototype = {
+ /**
+ * The width of the plugin area in pixels, excluding any visible scrollbars,
+ * @type {number}
+ */
+ get width() {
+ return this.widthPercent * this.pdfPlugin_.offsetWidth;
+ },
+
+ /**
+ * The height of the plugin area in pixels, excluding any visible
+ * scrollbars.
+ * @type {number}
+ */
+ get height() {
+ return this.heightPercent * this.pdfPlugin_.offsetHeight;
+ },
+
+ /**
+ * The width of the plugin area in percent, excluding any visible
+ * scrollbars.
+ * @type {number}
+ */
+ get widthPercent() {
+ var width = this.pdfPlugin_.getWidth();
+ var scrollbarWidth = this.pdfPlugin_.getVerticalScrollbarThickness();
+ return (width - scrollbarWidth) / width;
+ },
+
+ /**
+ * The height of the plugin area in percent, excluding any visible
+ * scrollbars.
+ * @type {number}
+ */
+ get heightPercent() {
+ var height = this.pdfPlugin_.getHeight();
+ var scrollbarHeight = this.pdfPlugin_.getHorizontalScrollbarThickness();
+ return (height - scrollbarHeight) / height;
+ },
+
+ get pdfLoaded() {
+ return this.pdfLoaded_;
+ },
+
+ set pdfLoaded(pdfLoaded) {
+ this.pdfLoaded_ = pdfLoaded;
+ },
+
+ /**
+ * @return {print_preview.Rect} A rectangle describing the postion of the
+ * most visible page normalized with respect to the total height and width
+ * of the plugin.
+ */
+ getPageLocationNormalized: function() {
+ var pluginLocation =
+ this.pdfPlugin_.getPageLocationNormalized().split(';');
+ return 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.pdfPlugin_) {
+ this.zoomLevel_ = this.pdfPlugin_.getZoomLevel();
+ this.pageOffset_ = {
+ x: this.pdfPlugin_.pageXOffset(),
+ y: this.pdfPlugin_.pageYOffset()
+ };
+ }
+ this.pdfLoaded_ = false;
+ },
+
+ /**
+ * Adds event listeners for various events.
+ * @private
+ */
+ addEventListeners: function() {
+ document.addEventListener('PDFLoaded',
+ this.onPDFLoaded_.bind(this));
+ },
+
+ /**
+ * Listener executing when a PDFLoaded event occurs.
+ * @private
+ */
+ onPDFLoaded_: function() {
+ this.pdfPlugin_ = $('pdf-viewer');
+ this.pdfLoaded_ = true;
+ if (this.zoomLevel_ != null && this.pageOffset_ != null) {
+ this.pdfPlugin_.setZoomLevel(this.zoomLevel_);
+ this.pdfPlugin_.setPageXOffset(this.pageOffset_.x);
+ this.pdfPlugin_.setPageYOffset(this.pageOffset_.y);
+ } else {
+ this.pdfPlugin_.fitToHeight();
+ }
+ }
+ };
+
+ return {
+ PreviewArea: PreviewArea,
+ };
+});
diff --git a/chrome/browser/resources/print_preview/print_header.js b/chrome/browser/resources/print_preview/print_header.js
index 76fbdab..92bf086 100644
--- a/chrome/browser/resources/print_preview/print_header.js
+++ b/chrome/browser/resources/print_preview/print_header.js
@@ -100,6 +100,11 @@ cr.define('print_preview', function() {
return;
}
+ if (!marginSettings.areMarginSettingsValid()) {
+ this.summary_.innerHTML = '';
+ return;
+ }
+
var pageSet = pageSettings.selectedPagesSet;
var numOfSheets = pageSet.length;
var summaryLabel =
diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css
index 69fd060..1808f63 100644
--- a/chrome/browser/resources/print_preview/print_preview.css
+++ b/chrome/browser/resources/print_preview/print_preview.css
@@ -722,6 +722,45 @@ select {
pointer-events: none;
}
+input[type='text'].margin-box {
+ background-color: #2a2a2a;
+ color: #fff;
+ cursor: auto;
+ font-family: arial;
+ font-size: 10px;
+ height: 15px;
+ padding: 5px 10px;
+ position: absolute;
+ text-align: center;
+ width: 40px;
+ z-index: 3;
+}
+
+input[type='text'].margin-box.invalid {
+ background-color: #c11b17;
+}
+
+.draggable-area {
+ background-color: transparent;
+ border-color: transparent;
+ pointer-events: none;
+ position: absolute;
+ z-index: 2;
+}
+
+.margin-line {
+ border-color: #4080FA;
+ border-style: dashed;
+ border-width: 1px;
+ position: absolute;
+ z-index: 2;
+}
+
+#customized-margins {
+ position: absolute;
+ top: 0;
+}
+
#messages {
color: #404040;
font-size: 13px;
diff --git a/chrome/browser/resources/print_preview/print_preview.html b/chrome/browser/resources/print_preview/print_preview.html
index 083c60d..83b5757 100644
--- a/chrome/browser/resources/print_preview/print_preview.html
+++ b/chrome/browser/resources/print_preview/print_preview.html
@@ -38,10 +38,8 @@
<hr>
<include src="color_settings.html"></include>
<hr>
- <div id="display-margin-options" hidden>
- <include src="margin_settings.html"></include>
- <hr>
- </div>
+ <include src="margin_settings.html"></include>
+ <hr>
<include src="header_footer_settings.html"></include>
<hr>
<div id="system-dialog-div">
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index 55f212d..c3bfbca 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -53,27 +53,32 @@ var isPrintReadyMetafileReady = false;
// True when preview tab is hidden.
var isTabHidden = false;
-// Object holding the print and cancel buttons.
+// @type {print_preview.PrintHeader} Holds the print and cancel buttons.
var printHeader;
-// Object holding all the pages related settings.
+// @type {print_preview.PageSettings} Holds all the pages related settings.
var pageSettings;
-// Object holding all the copies related settings.
+// @type {print_preview.CopiesSettings} Holds all the copies related settings.
var copiesSettings;
-// Object holding all the layout related settings.
+// @type {print_preview.LayoutSettings} Holds all the layout related settings.
var layoutSettings;
-// Object holding all the margin related settings.
+// @type {print_preview.MarginSettings} Holds all the margin related settings.
var marginSettings;
-// Object holding all the header footer related settings.
+// @type {print_preview.HeaderFooterSettings} Holds all the header footer
+// related settings.
var headerFooterSettings;
-// Object holding all the color related settings.
+// @type {print_preview.ColorSettings} Holds all the color related settings.
var colorSettings;
+// @type {print_preview.PreviewArea} Holds information related to the preview
+// area (on the right).
+var previewArea;
+
// True if the user has click 'Advanced...' in order to open the system print
// dialog.
var showingSystemDialog = false;
@@ -130,12 +135,14 @@ function onLoad() {
marginSettings = print_preview.MarginSettings.getInstance();
headerFooterSettings = print_preview.HeaderFooterSettings.getInstance();
colorSettings = print_preview.ColorSettings.getInstance();
+ previewArea = print_preview.PreviewArea.getInstance();
pageSettings.addEventListeners();
copiesSettings.addEventListeners();
headerFooterSettings.addEventListeners();
layoutSettings.addEventListeners();
marginSettings.addEventListeners();
colorSettings.addEventListeners();
+ previewArea.addEventListeners();
$('printer-list').onchange = updateControlsWithSelectedPrinterCapabilities;
showLoadingAnimation();
@@ -321,8 +328,8 @@ function finishedCloudPrinting() {
function areSettingsValid() {
var selectedPrinter = getSelectedPrinterName();
return pageSettings.isPageSelectionValid() &&
- (copiesSettings.isValid() ||
- selectedPrinter == PRINT_TO_PDF ||
+ marginSettings.areMarginSettingsValid() &&
+ (copiesSettings.isValid() || selectedPrinter == PRINT_TO_PDF ||
selectedPrinter == PRINT_WITH_CLOUD_PRINT);
}
@@ -504,6 +511,7 @@ function requestPrintPreview() {
printSettings.save();
layoutSettings.updateState();
+ previewArea.resetState();
isPrintReadyMetafileReady = false;
isFirstPageLoaded = false;
@@ -762,7 +770,6 @@ function onPDFLoad() {
if (previewModifiable) {
setPluginPreviewPageCount();
}
- $('pdf-viewer').fitToHeight();
cr.dispatchSimpleEvent(document, 'PDFLoaded');
isFirstPageLoaded = true;
checkAndHideOverlayLayerIfValid();
@@ -794,8 +801,18 @@ function onDidGetPreviewPageCount(pageCount, isModifiable, previewResponseId) {
cr.dispatchSimpleEvent(document, 'updateSummary');
}
+/**
+ * @param {printing::PageSizeMargins} pageLayout The default layout of the page
+ * in points.
+ */
function onDidGetDefaultPageLayout(pageLayout) {
- // TODO(aayushkumar): Do something here!
+ marginSettings.currentDefaultPageLayout = new print_preview.PageLayout(
+ pageLayout.contentWidth,
+ pageLayout.contentHeight,
+ pageLayout.marginLeft,
+ pageLayout.marginTop,
+ pageLayout.marginRight,
+ pageLayout.marginBottom);
}
/**
@@ -971,21 +988,48 @@ function createPDFPlugin(srcDataIndex) {
pdfViewer.setAttribute('aria-atomic', 'true');
$('mainview').appendChild(pdfViewer);
pdfViewer.onload('onPDFLoad()');
+ pdfViewer.onScroll('onPreviewPositionChanged()');
+ pdfViewer.onPluginSizeChanged('onPreviewPositionChanged()');
pdfViewer.removePrintButton();
pdfViewer.grayscale(true);
}
/**
+ * Called either when there is a scroll event or when the plugin size changes.
+ */
+function onPreviewPositionChanged() {
+ marginSettings.onPreviewPositionChanged();
+}
+
+/**
* @return {boolean} true if a compatible pdf plugin exists.
*/
function checkCompatiblePluginExists() {
- var dummyPlugin = $('dummy-viewer')
- return !!(dummyPlugin.onload &&
- dummyPlugin.goToPage &&
- dummyPlugin.removePrintButton &&
- dummyPlugin.loadPreviewPage &&
- dummyPlugin.printPreviewPageCount &&
- dummyPlugin.resetPrintPreviewUrl);
+ var dummyPlugin = $('dummy-viewer');
+ var pluginInterface = [ dummyPlugin.onload,
+ dummyPlugin.goToPage,
+ dummyPlugin.removePrintButton,
+ dummyPlugin.loadPreviewPage,
+ dummyPlugin.printPreviewPageCount,
+ dummyPlugin.resetPrintPreviewUrl,
+ dummyPlugin.onPluginSizeChanged,
+ dummyPlugin.onScroll,
+ dummyPlugin.pageXOffset,
+ dummyPlugin.pageYOffset,
+ dummyPlugin.setZoomLevel,
+ dummyPlugin.setPageXOffset,
+ dummyPlugin.setPageYOffset,
+ dummyPlugin.getHorizontalScrollbarThickness,
+ dummyPlugin.getVerticalScrollbarThickness,
+ dummyPlugin.getPageLocationNormalized,
+ dummyPlugin.getHeight,
+ dummyPlugin.getWidth ];
+
+ for (var i = 0; i < pluginInterface.length; i++) {
+ if (!pluginInterface[i])
+ return false;
+ }
+ return true;
}
/**
@@ -1063,3 +1107,8 @@ window.onkeydown = onKeyDown;
<include src="layout_settings.js"/>
<include src="color_settings.js"/>
<include src="margin_settings.js"/>
+<include src="margin_textbox.js"/>
+<include src="margin_line.js"/>
+<include src="margin_utils.js"/>
+<include src="margins_ui.js"/>
+<include src="preview_area.js"/>
diff --git a/chrome/browser/resources/print_preview/print_preview_utils.js b/chrome/browser/resources/print_preview/print_preview_utils.js
index 594769e..90ecd16 100644
--- a/chrome/browser/resources/print_preview/print_preview_utils.js
+++ b/chrome/browser/resources/print_preview/print_preview_utils.js
@@ -203,3 +203,24 @@ function randomInteger(endPointA, endPointB) {
to = Math.max(endPointA, endPointB);
return Math.floor(Math.random() * (to - from + 1) + from);
}
+
+// Number of points per inch.
+POINTS_PER_INCH = 72;
+
+/**
+ * Converts |value| from inches to points.
+ * @param {number} value The number in inches.
+ * @return {number} |value| in points.
+ */
+function convertInchesToPoints(value) {
+ return value * POINTS_PER_INCH;
+}
+
+/**
+ * Converts |value| from points to inches.
+ * @param {number} value The number in points.
+ * @return {number} |value| in inches.
+ */
+function convertPointsToInches(value) {
+ return value / POINTS_PER_INCH;
+}
diff --git a/chrome/browser/resources/print_preview/print_preview_utils_test.html b/chrome/browser/resources/print_preview/print_preview_utils_test.html
index 58994ed..c633954 100644
--- a/chrome/browser/resources/print_preview/print_preview_utils_test.html
+++ b/chrome/browser/resources/print_preview/print_preview_utils_test.html
@@ -105,6 +105,18 @@ function testPageSetToPageRanges() {
assertEquals(pageRanges[2].to, 11);
}
+function testConvertInchesToPoints() {
+ assertEquals(convertInchesToPoints(1), 72);
+ assertEquals(convertInchesToPoints(2), 144);
+ assertEquals(convertInchesToPoints(0.45), 32.4);
+}
+
+function testConvertPointsToInches() {
+ assertEquals(convertPointsToInches(72), 1);
+ assertEquals(convertPointsToInches(144), 2);
+ assertEquals(convertPointsToInches(32.4), 0.45);
+}
+
</script>
</body>
</html>