Index: chrome/browser/resources/print_preview/margin_settings.js |
diff --git a/chrome/browser/resources/print_preview/margin_settings.js b/chrome/browser/resources/print_preview/margin_settings.js |
index f9d81a3053927d16cfb72ae8662cbff1d0e08e9f..5f48ed79436849ad7b99a61aa0332341f76dacc6 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, |
}; |
}); |