summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/print_preview
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/resources/print_preview')
-rw-r--r--chrome/browser/resources/print_preview/cloud_print_interface.js304
-rw-r--r--chrome/browser/resources/print_preview/color_settings.html14
-rw-r--r--chrome/browser/resources/print_preview/color_settings.js108
-rw-r--r--chrome/browser/resources/print_preview/component.js192
-rw-r--r--chrome/browser/resources/print_preview/copies_settings.html27
-rw-r--r--chrome/browser/resources/print_preview/copies_settings.js248
-rw-r--r--chrome/browser/resources/print_preview/data/capabilities_holder.js43
-rw-r--r--chrome/browser/resources/print_preview/data/chromium_capabilities.js180
-rw-r--r--chrome/browser/resources/print_preview/data/cloud_capabilities.js413
-rw-r--r--chrome/browser/resources/print_preview/data/cloud_parsers.js207
-rw-r--r--chrome/browser/resources/print_preview/data/coordinate2d.js76
-rw-r--r--chrome/browser/resources/print_preview/data/destination.js188
-rw-r--r--chrome/browser/resources/print_preview/data/destination_store.js192
-rw-r--r--chrome/browser/resources/print_preview/data/document_info.js55
-rw-r--r--chrome/browser/resources/print_preview/data/local_parsers.js70
-rw-r--r--chrome/browser/resources/print_preview/data/margins.js86
-rw-r--r--chrome/browser/resources/print_preview/data/measurement_system.js159
-rw-r--r--chrome/browser/resources/print_preview/data/measurement_system_unittest.gtestjs68
-rw-r--r--chrome/browser/resources/print_preview/data/page_number_set.js105
-rw-r--r--chrome/browser/resources/print_preview/data/print_ticket_store.js629
-rw-r--r--chrome/browser/resources/print_preview/data/printable_area.js64
-rw-r--r--chrome/browser/resources/print_preview/data/size.js56
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/collate.js57
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/color.js71
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/copies.js70
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js171
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/duplex.js57
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/fit_to_page.js69
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/header_footer.js95
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/landscape.js72
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/margins_type.js68
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/page_range.js70
-rw-r--r--chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js95
-rw-r--r--chrome/browser/resources/print_preview/fit_to_page_settings.js114
-rw-r--r--chrome/browser/resources/print_preview/header_footer_settings.js128
-rw-r--r--chrome/browser/resources/print_preview/layout_settings.html13
-rw-r--r--chrome/browser/resources/print_preview/layout_settings.js120
-rw-r--r--chrome/browser/resources/print_preview/margin_settings.js705
-rw-r--r--chrome/browser/resources/print_preview/margin_textbox.js217
-rw-r--r--chrome/browser/resources/print_preview/margin_utils.js187
-rw-r--r--chrome/browser/resources/print_preview/margins.css100
-rw-r--r--chrome/browser/resources/print_preview/margins_ui.js213
-rw-r--r--chrome/browser/resources/print_preview/margins_ui_pair.js296
-rw-r--r--chrome/browser/resources/print_preview/more_options.html17
-rw-r--r--chrome/browser/resources/print_preview/more_options.js93
-rw-r--r--chrome/browser/resources/print_preview/native_layer.js727
-rw-r--r--chrome/browser/resources/print_preview/page_settings.html21
-rw-r--r--chrome/browser/resources/print_preview/page_settings.js378
-rw-r--r--chrome/browser/resources/print_preview/preview_area.js299
-rw-r--r--chrome/browser/resources/print_preview/preview_generator.js392
-rw-r--r--chrome/browser/resources/print_preview/previewarea/margin_control.css91
-rw-r--r--chrome/browser/resources/print_preview/previewarea/margin_control.html6
-rw-r--r--chrome/browser/resources/print_preview/previewarea/margin_control.js467
-rw-r--r--chrome/browser/resources/print_preview/previewarea/margin_control_container.css12
-rw-r--r--chrome/browser/resources/print_preview/previewarea/margin_control_container.js446
-rw-r--r--chrome/browser/resources/print_preview/previewarea/preview_area.css75
-rw-r--r--chrome/browser/resources/print_preview/previewarea/preview_area.html41
-rw-r--r--chrome/browser/resources/print_preview/previewarea/preview_area.js592
-rw-r--r--chrome/browser/resources/print_preview/print_header.css15
-rw-r--r--chrome/browser/resources/print_preview/print_header.html10
-rw-r--r--chrome/browser/resources/print_preview/print_header.js280
-rw-r--r--chrome/browser/resources/print_preview/print_preview.css194
-rw-r--r--chrome/browser/resources/print_preview/print_preview.html131
-rw-r--r--chrome/browser/resources/print_preview/print_preview.js2157
-rw-r--r--chrome/browser/resources/print_preview/print_preview_cloud.js455
-rw-r--r--chrome/browser/resources/print_preview/print_preview_utils.js82
-rw-r--r--chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs26
-rw-r--r--chrome/browser/resources/print_preview/settings/color_settings.html17
-rw-r--r--chrome/browser/resources/print_preview/settings/color_settings.js133
-rw-r--r--chrome/browser/resources/print_preview/settings/copies_settings.css56
-rw-r--r--chrome/browser/resources/print_preview/settings/copies_settings.html31
-rw-r--r--chrome/browser/resources/print_preview/settings/copies_settings.js327
-rw-r--r--chrome/browser/resources/print_preview/settings/destination_settings.html6
-rw-r--r--chrome/browser/resources/print_preview/settings/destination_settings.js199
-rw-r--r--chrome/browser/resources/print_preview/settings/layout_settings.html18
-rw-r--r--chrome/browser/resources/print_preview/settings/layout_settings.js124
-rw-r--r--chrome/browser/resources/print_preview/settings/margin_settings.html (renamed from chrome/browser/resources/print_preview/margin_settings.html)6
-rw-r--r--chrome/browser/resources/print_preview/settings/margin_settings.js112
-rw-r--r--chrome/browser/resources/print_preview/settings/other_options_settings.html20
-rw-r--r--chrome/browser/resources/print_preview/settings/other_options_settings.js172
-rw-r--r--chrome/browser/resources/print_preview/settings/page_settings.css13
-rw-r--r--chrome/browser/resources/print_preview/settings/page_settings.html23
-rw-r--r--chrome/browser/resources/print_preview/settings/page_settings.js247
83 files changed, 9521 insertions, 5462 deletions
diff --git a/chrome/browser/resources/print_preview/cloud_print_interface.js b/chrome/browser/resources/print_preview/cloud_print_interface.js
new file mode 100644
index 0000000..b7e7c7c
--- /dev/null
+++ b/chrome/browser/resources/print_preview/cloud_print_interface.js
@@ -0,0 +1,304 @@
+// 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('cloudprint', function() {
+ 'use strict';
+
+ /**
+ * API to the Google Cloud Print service.
+ * @param {string} baseUrl Base part of the Google Cloud Print service URL
+ * with no trailing slash. For example,
+ * 'https://www.google.com/cloudprint'.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+ function CloudPrintInterface(baseUrl) {
+ /**
+ * The base URL of the Google Cloud Print API.
+ * @type {string}
+ * @private
+ */
+ this.baseURL_ = baseUrl;
+
+ /**
+ * Last received XSRF token. Sent as a parameter in every request.
+ * @type {string}
+ * @private
+ */
+ this.xsrfToken_ = '';
+ };
+
+ /**
+ * Event types dispatched by the interface.
+ * @enum {string}
+ */
+ CloudPrintInterface.EventType = {
+ ERROR: 'cloudprint.CloudPrintInterface.ERROR',
+ PRINTER_DONE: 'cloudprint.CloudPrintInterface.PRINTER_DONE',
+ SEARCH_DONE: 'cloudprint.CloudPrintInterface.SEARCH_DONE',
+ SUBMIT_DONE: 'cloudprint.CloudPrintInterface.SUBMIT_DONE'
+ };
+
+ /**
+ * Content type header value for a URL encoded HTTP request.
+ * @type {string}
+ * @private
+ */
+ CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_ =
+ 'application/x-www-form-urlencoded';
+
+ /**
+ * Content type header value for a multipart HTTP request.
+ * @type {string}
+ * @private
+ */
+ CloudPrintInterface.MULTIPART_CONTENT_TYPE_ =
+ 'multipart/form-data; boundary=----CloudPrintFormBoundaryjc9wuprokl8i';
+
+ /**
+ * Enumeration of JSON response fields from Google Cloud Print API.
+ * @enum {string}
+ * @private
+ */
+ CloudPrintInterface.JsonFields_ = {
+ PRINTER: 'printer'
+ };
+
+ CloudPrintInterface.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ /**
+ * Sends a Google Cloud Print search API request.
+ * @param {boolean} isRecent Whether to search for only recently used
+ * printers.
+ */
+ search: function(isRecent) {
+ var params = {};
+ if (isRecent) {
+ params['q'] = '^recent';
+ }
+ this.sendRequest_('GET', 'search', params, null, this.onSearchDone_);
+ },
+
+ /**
+ * Sends a Google Cloud Print submit API request.
+ * @param {string} body Body of the HTTP post request to send.
+ */
+ submit: function(body) {
+ this.sendRequest_('POST', 'submit', null, body, this.onSubmitDone_);
+ },
+
+ /**
+ * Sends a Google Cloud Print printer API request.
+ * @param {string} printerId ID of the printer to lookup.
+ */
+ printer: function(printerId) {
+ var params = {'printerid': printerId};
+ this.sendRequest_('GET', 'printer', params, null, this.onPrinterDone_);
+ },
+
+ /**
+ * Creates an object that represents a Google Cloud Print print ticket.
+ * @param {!print_preview.Destination} destination Destination to print to.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to create
+ * the state of the print ticket.
+ * @return {object} Google Cloud Print print ticket.
+ */
+ createPrintTicket: function(destination, printTicketStore) {
+ assert(!destination.isLocal,
+ 'Trying to create a Google Cloud Print print ticket for a local ' +
+ 'destination');
+ assert(destination.capabilities,
+ 'Trying to create a Google Cloud Print print ticket for a ' +
+ 'destination with no print capabilities');
+
+ var ticketItems = [];
+
+ if (destination.capabilities.collateCapability) {
+ var collateCap = destination.capabilities.collateCapability;
+ var ticketItem = {
+ 'name': collateCap.id,
+ 'type': collateCap.type,
+ 'options': [{'name': printTicketStore.isCollateEnabled() ?
+ collateCap.collateOption : collateCap.noCollateOption}]
+ };
+ ticketItems.push(ticketItem);
+ }
+
+ if (destination.capabilities.colorCapability) {
+ var colorCap = destination.capabilities.colorCapability;
+ var ticketItem = {
+ 'name': colorCap.id,
+ 'type': colorCap.type,
+ 'options': [{'name': printTicketStore.isColorEnabled() ?
+ colorCap.colorOption : colorCap.bwOption}]
+ };
+ ticketItems.push(ticketItem);
+ }
+
+ if (destination.capabilities.copiesCapability) {
+ var copiesCap = destination.capabilities.copiesCapability;
+ var ticketItem = {
+ 'name': copiesCap.id,
+ 'type': copiesCap.type,
+ 'value': printTicketStore.getCopies()
+ };
+ ticketItems.push(ticketItem);
+ }
+
+ if (destination.capabilities.duplexCapability) {
+ var duplexCap = destination.capabilities.duplexCapability;
+ var ticketItem = {
+ 'name': duplexCap.id,
+ 'type': duplexCap.type,
+ 'options': [{'name': printTicketStore.isDuplexEnabled() ?
+ duplexCap.longEdgeOption : duplexCap.simplexOption}]
+ };
+ ticketItems.push(ticketItem);
+ }
+
+ return {
+ 'capabilities': ticketItems
+ };
+ },
+
+ /**
+ * Sends a request to the Google Cloud Print API.
+ * @param {string} method HTTP method of the request.
+ * @param {string} action Google Cloud Print action to perform.
+ * @param {Object} params HTTP parameters to include in the request.
+ * @param {string} body HTTP multi-part encoded body.
+ * @param {function(Object)} successCallback Callback to invoke when request
+ * completes successfully.
+ */
+ sendRequest_: function(method, action, params, body, successCallback) {
+ if (!this.xsrfToken_) {
+ // TODO(rltoscano): Should throw an error if not a read-only action or
+ // issue an xsrf token request.
+ }
+ var url = this.baseURL_ + '/' + action + '?xsrf=' + this.xsrfToken_;
+
+ if (params) {
+ for (var paramName in params) {
+ url += '&' + paramName + '=' + encodeURIComponent(params[paramName]);
+ }
+ }
+
+ var headers = {};
+ headers['X-CloudPrint-Proxy'] = 'ChromePrintPreview';
+ if (method == 'GET') {
+ headers['Content-Type'] = CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_;
+ } else if (method == 'POST') {
+ headers['Content-Type'] = CloudPrintInterface.MULTIPART_CONTENT_TYPE_;
+ }
+
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = this.onReadyStateChange_.bind(
+ this, xhr, successCallback.bind(this));
+ xhr.open(method, url, true);
+ xhr.withCredentials = true;
+ for (var header in headers) {
+ xhr.setRequestHeader(header, headers[header]);
+ }
+ xhr.send(body);
+ },
+
+ /**
+ * Dispatches an ERROR event with the given error message.
+ * @param {string} message Error message to include in the ERROR event.
+ * @private
+ */
+ dispatchErrorEvent_: function(message) {
+ var errorEvent = new cr.Event(CloudPrintInterface.EventType.ERROR);
+ errorEvent.message = message;
+ this.dispatchEvent(errorEvent);
+ },
+
+ /**
+ * Called when the ready-state of a XML http request changes.
+ * Calls the successCallback with the result or dispatches an ERROR event.
+ * @param {XMLHttpRequest} xhr XML http request that changed.
+ * @param {function(Object)} successCallback Callback to call if the request
+ * was successful.
+ * @private
+ */
+ onReadyStateChange_: function(xhr, successCallback) {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ var result = JSON.parse(xhr.responseText);
+ if (result['success']) {
+ this.xsrfToken_ = result['xsrf_token'];
+ successCallback(result);
+ } else {
+ this.dispatchErrorEvent_(result['message']);
+ }
+ } else {
+ this.dispatchErrorEvent_(xhr.status + '');
+ }
+ }
+ },
+
+ /**
+ * Called when the search request completes successfully.
+ * @param {Object} result JSON response.
+ * @private
+ */
+ onSearchDone_: function(result) {
+ var printerListJson = result['printers'] || [];
+ var printerList = [];
+ for (var printerJson, i = 0; printerJson = printerListJson[i]; i++) {
+ try {
+ printerList.push(
+ cloudprint.CloudDestinationParser.parse(printerJson));
+ } catch (err) {
+ console.error('Unable to parse cloud print destination: ' + err);
+ }
+ }
+ var isRecent = result['request']['params']['q'] == '^recent';
+ var searchDoneEvent =
+ new cr.Event(CloudPrintInterface.EventType.SEARCH_DONE);
+ searchDoneEvent.printers = printerList;
+ searchDoneEvent.isRecent = isRecent;
+ searchDoneEvent.email = result['request']['user'];
+ this.dispatchEvent(searchDoneEvent);
+ },
+
+ /**
+ * Called when the submit request completes successfully.
+ * @param {Object} result JSON response.
+ * @private
+ */
+ onSubmitDone_: function(result) {
+ this.dispatchEvent(
+ new cr.Event(CloudPrintInterface.EventType.SUBMIT_DONE));
+ },
+
+ /**
+ * Called when the printer request completes successfully.
+ * @param {Object} result JSON response.
+ * @private
+ */
+ onPrinterDone_: function(result) {
+ // TODO(rltoscano): Better error handling here.
+ var printerJson = result['printers'][0];
+ var printer;
+ try {
+ printer = cloudprint.CloudDestinationParser.parse(printerJson);
+ } catch (err) {
+ console.error('Failed to parse cloud print destination: ' +
+ JSON.stringify(printerJson));
+ return;
+ }
+ var printerDoneEvent =
+ new cr.Event(CloudPrintInterface.EventType.PRINTER_DONE);
+ printerDoneEvent.printer = printer;
+ this.dispatchEvent(printerDoneEvent);
+ }
+ };
+
+ // Export
+ return {
+ CloudPrintInterface: CloudPrintInterface
+ };
+});
diff --git a/chrome/browser/resources/print_preview/color_settings.html b/chrome/browser/resources/print_preview/color_settings.html
deleted file mode 100644
index 7eadd0a..0000000
--- a/chrome/browser/resources/print_preview/color_settings.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<div id="color-option" class="two-column visible" aria-hidden="true"
- aria-live="polite">
- <h1 i18n-content="optionColor"></h1>
- <div class="right-column">
- <div class="radio"><label>
- <input id="color" type="radio" name="color">
- <span i18n-content="optionColor"></span>
- </label></div>
- <div class="radio"><label>
- <input id="bw" type="radio" name="color" checked>
- <span i18n-content="optionBw"></span>
- </label></div>
- </div>
- </div>
diff --git a/chrome/browser/resources/print_preview/color_settings.js b/chrome/browser/resources/print_preview/color_settings.js
deleted file mode 100644
index 2d9cdc2..0000000
--- a/chrome/browser/resources/print_preview/color_settings.js
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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 ColorSettings object. This object encapsulates all settings and
- * logic related to color selection (color/bw).
- * @constructor
- */
- function ColorSettings() {
- this.colorOption_ = $('color-option');
- this.colorRadioButton_ = $('color');
- this.bwRadioButton_ = $('bw');
-
- this.printerColorModelForColor_ = ColorSettings.COLOR;
- this.printerColorModelForBlack_ = ColorSettings.GRAY;
- this.addEventListeners_();
- }
-
- ColorSettings.GRAY = 1;
- ColorSettings.COLOR = 2;
- cr.addSingletonGetter(ColorSettings);
-
- ColorSettings.prototype = {
- /**
- * The radio button corresponding to the color option.
- * @type {HTMLInputElement}
- */
- get colorRadioButton() {
- return this.colorRadioButton_;
- },
-
- /**
- * The radio button corresponding to the black and white option.
- * @type {HTMLInputElement}
- */
- get bwRadioButton() {
- return this.bwRadioButton_;
- },
-
- /**
- * @return {number} The color mode for print preview.
- */
- get colorMode() {
- return this.bwRadioButton_.checked ?
- this.printerColorModelForBlack_ :
- this.printerColorModelForColor_;
- },
-
- /**
- * Adding listeners to all color related controls. The listeners take care
- * of altering their behavior depending on |hasPendingPreviewRequest|.
- * @private
- */
- addEventListeners_: function() {
- this.colorRadioButton_.onclick = function() {
- setColor(true);
- };
- this.bwRadioButton_.onclick = function() {
- setColor(false);
- };
- document.addEventListener(customEvents.PDF_LOADED,
- this.onPDFLoaded_.bind(this));
- document.addEventListener(customEvents.PRINTER_CAPABILITIES_UPDATED,
- this.onPrinterCapabilitiesUpdated_.bind(this));
- },
-
- /**
- * Executes when a |customEvents.PRINTER_CAPABILITIES_UPDATED| event occurs.
- * @private
- */
- onPrinterCapabilitiesUpdated_: function(e) {
- var disableColorOption = e.printerCapabilities.disableColorOption;
-
- disableColorOption ? fadeOutOption(this.colorOption_) :
- fadeInOption(this.colorOption_);
- this.colorOption_.setAttribute('aria-hidden', disableColorOption);
-
- var setColorAsDefault = e.printerCapabilities.setColorAsDefault;
- this.printerColorModelForColor_ =
- e.printerCapabilities.printerColorModelForColor ||
- ColorSettings.COLOR;
- this.printerColorModelForBlack_ =
- e.printerCapabilities.printerColorModelForBlack ||
- ColorSettings.GRAY;
-
- this.colorRadioButton_.checked = setColorAsDefault;
- this.bwRadioButton_.checked = !setColorAsDefault;
- setColor(this.colorRadioButton_.checked);
- },
-
- /**
- * Executes when a |customEvents.PDF_LOADED| event occurs.
- * @private
- */
- onPDFLoaded_: function() {
- setColor(this.colorRadioButton_.checked);
- }
-
- };
-
- return {
- ColorSettings: ColorSettings
- };
-});
diff --git a/chrome/browser/resources/print_preview/component.js b/chrome/browser/resources/print_preview/component.js
new file mode 100644
index 0000000..f51c3ae1
--- /dev/null
+++ b/chrome/browser/resources/print_preview/component.js
@@ -0,0 +1,192 @@
+// 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';
+
+ /**
+ * Class that represents a UI component.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+ function Component() {
+ cr.EventTarget.call(this);
+
+ /**
+ * Component's HTML element.
+ * @type {Element}
+ * @private
+ */
+ this.element_ = null;
+
+ this.isInDocument_ = false;
+
+ /**
+ * Component's event tracker.
+ * @type {EventTracker}
+ * @private
+ */
+ this.tracker_ = new EventTracker();
+
+ /**
+ * Child components of the component.
+ * @type {Array.<print_preview.Component>}
+ * @private
+ */
+ this.children_ = [];
+ };
+
+ Component.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ /** Gets the component's element. */
+ getElement: function() {
+ return this.element_;
+ },
+
+ /** @return {EventTracker} Component's event tracker. */
+ get tracker() {
+ return this.tracker_;
+ },
+
+ /**
+ * @return {boolean} Whether the element of the component is already in the
+ * HTML document.
+ */
+ get isInDocument() {
+ return this.isInDocument_;
+ },
+
+ /**
+ * Creates the root element of the component. Sub-classes should override
+ * this method.
+ */
+ createDom: function() {
+ this.element_ = cr.doc.createElement('div');
+ },
+
+ /**
+ * Called when the component's element is known to be in the document.
+ * Anything using document.getElementById etc. should be done at this stage.
+ * Sub-classes should extend this method and attach listeners.
+ */
+ enterDocument: function() {
+ this.isInDocument_ = true;
+ for (var child, i = 0; child = this.children_[i]; i++) {
+ if (!child.isInDocument && child.getElement()) {
+ child.enterDocument();
+ }
+ }
+ },
+
+ /** Removes all event listeners. */
+ exitDocument: function() {
+ for (var child, i = 0; child = this.children_[i]; i++) {
+ if (child.isInDocument) {
+ child.exitDocument();
+ }
+ }
+ this.tracker_.removeAll();
+ this.isInDocument_ = false;
+ },
+
+ /**
+ * Renders this UI component and appends the element to the given parent
+ * element.
+ * @param {!Element} parentElement Element to render the component's
+ * element into.
+ */
+ render: function(parentElement) {
+ assert(!this.isInDocument, 'Component is already in the document');
+ if (!this.element_) {
+ this.createDom();
+ }
+ parentElement.appendChild(this.element_);
+ this.enterDocument();
+ },
+
+ /**
+ * Decorates an existing DOM element. Sub-classes should override the
+ * override the decorateInternal method.
+ * @param {Element} element Element to decorate.
+ */
+ decorate: function(element) {
+ assert(!this.isInDocument, 'Component is already in the document');
+ this.setElementInternal(element);
+ this.decorateInternal();
+ this.enterDocument();
+ },
+
+ /**
+ * @param {print_preview.Component} child Component to add as a child of
+ * this component.
+ */
+ addChild: function(child) {
+ this.children_.push(child);
+ },
+
+ /**
+ * @param {!print_preview.Component} child Component to remove from this
+ * component's children.
+ */
+ removeChild: function(child) {
+ var childIdx = this.children_.indexOf(child);
+ if (childIdx != -1) {
+ this.children_.splice(childIdx, 1);
+ }
+ if (child.isInDocument) {
+ child.exitDocument();
+ if (child.getElement()) {
+ child.getElement().parentNode.removeChild(child.getElement());
+ }
+ }
+ },
+
+ /** Removes all of the component's children. */
+ removeChildren: function() {
+ while (this.children_.length > 0) {
+ this.removeChild(this.children_[0]);
+ }
+ },
+
+ /**
+ * Sets the component's element.
+ * @param {Element} element HTML element to set as the component's element.
+ * @protected
+ */
+ setElementInternal: function(element) {
+ this.element_ = element;
+ },
+
+ /**
+ * Decorates the given element for use as the element of the component.
+ * @protected
+ */
+ decorateInternal: function() { /*abstract*/ },
+
+ /**
+ * Clones a template HTML DOM tree.
+ * @param {string} templateId Template element ID.
+ * @param {boolean=} opt_keepHidden Whether to leave the cloned template
+ * hidden after cloning.
+ * @return {Element} Cloned element with its 'id' attribute stripped.
+ * @protected
+ */
+ cloneTemplateInternal: function(templateId, opt_keepHidden) {
+ var templateEl = $(templateId);
+ assert(templateEl != null,
+ 'Could not find element with ID: ' + templateId);
+ var el = templateEl.cloneNode(true);
+ el.id = '';
+ if (!opt_keepHidden) {
+ setIsVisible(el, true);
+ }
+ return el;
+ }
+ };
+
+ return {
+ Component: Component
+ };
+});
diff --git a/chrome/browser/resources/print_preview/copies_settings.html b/chrome/browser/resources/print_preview/copies_settings.html
deleted file mode 100644
index f368a6b..0000000
--- a/chrome/browser/resources/print_preview/copies_settings.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<div id="copies-option" class="two-column visible">
- <h1 i18n-content="copiesLabel"></h1>
- <div class="right-column">
- <div>
- <input id="copies" type="text" value="1" maxlength="3">
- <button id="increment"
- i18n-values="title:incrementTitle;">+</button>
- <button id="decrement"
- i18n-values="title:decrementTitle;">–</button>
- <div id="collate-option" class="checkbox" aria-live="polite" hidden>
- <label>
- <input id="collate" type="checkbox" checked>
- <span i18n-content="optionCollate"></span>
- </label>
- </div>
- </div>
- <span id="copies-hint" class="hint"
- i18n-content="copiesInstruction" aria-live="polite">
- </span>
- <div class="checkbox">
- <label id="two-sided-option" aria-live="polite">
- <input id="two-sided" type="checkbox">
- <span i18n-content="optionTwoSided"></span>
- </label>
- </div>
- </div>
-</div>
diff --git a/chrome/browser/resources/print_preview/copies_settings.js b/chrome/browser/resources/print_preview/copies_settings.js
deleted file mode 100644
index b5b94e9..0000000
--- a/chrome/browser/resources/print_preview/copies_settings.js
+++ /dev/null
@@ -1,248 +0,0 @@
-// 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 CopiesSettings object.
- * @constructor
- */
- function CopiesSettings() {
- this.copiesOption_ = $('copies-option');
- this.textfield_ = $('copies');
- this.incrementButton_ = $('increment');
- this.decrementButton_ = $('decrement');
- // Minimum allowed value for number of copies.
- this.minValue_ = 1;
- // Maximum allowed value for number of copies.
- this.maxValue_ = 999;
- this.collateOption_ = $('collate-option');
- this.collateCheckbox_ = $('collate');
- this.hint_ = $('copies-hint');
- this.twoSidedCheckbox_ = $('two-sided');
- this.twoSidedOption_ = $('two-sided-option');
-
- this.previousDuplexMode_ = CopiesSettings.UNKNOWN_DUPLEX_MODE;
- this.addEventListeners_();
- }
-
- // Constant values matches printing::DuplexMode enum.
- CopiesSettings.SIMPLEX = 0;
- CopiesSettings.LONG_EDGE = 1;
- CopiesSettings.UNKNOWN_DUPLEX_MODE = -1;
-
- cr.addSingletonGetter(CopiesSettings);
-
- CopiesSettings.prototype = {
- /**
- * The number of copies represented by the contents of |this.textfield_|.
- * If the text is not valid returns |this.minValue_|.
- * @type {number}
- */
- get numberOfCopies() {
- var value = parseInt(this.textfield_.value, 10);
- if (!value || value <= this.minValue_)
- value = this.minValue_;
- return value;
- },
-
- /**
- * Getter method for |collateOption_|.
- * @type {HTMLElement}
- */
- get collateOption() {
- return this.collateOption_;
- },
-
- /**
- * Getter method for |twoSidedCheckbox_|.
- * @type {HTMLInputElement}
- */
- get twoSidedCheckbox() {
- return this.twoSidedCheckbox_;
- },
-
- /**
- * Gets the duplex mode information for printing.
- * @return {number} duplex mode.
- */
- get duplexMode() {
- if (this.twoSidedOption_.hidden)
- return CopiesSettings.UNKNOWN_DUPLEX_MODE;
- else if (this.twoSidedCheckbox_.checked)
- return CopiesSettings.LONG_EDGE;
- else
- return CopiesSettings.SIMPLEX;
- },
-
- set previousDuplexMode(duplexMode) {
- this.previousDuplexMode_ = duplexMode;
- },
-
- /**
- * @return {boolean} true if |this.textfield_| is empty, or represents a
- * positive integer value.
- */
- isValid: function() {
- return !this.textfield_.value || isPositiveInteger(this.textfield_.value);
- },
-
- /**
- * Checks whether the preview collate setting value is set or not.
- * @return {boolean} true if collate option is enabled and checked.
- */
- isCollated: function() {
- return !this.collateOption_.hidden && this.collateCheckbox_.checked;
- },
-
- /**
- * Resets |this.textfield_| to |this.minValue_|.
- * @private
- */
- reset_: function() {
- this.textfield_.value = this.minValue_;
- },
-
- /**
- * Listener function to execute whenever the increment/decrement buttons are
- * clicked.
- * @private
- * @param {int} sign Must be 1 for an increment button click and -1 for a
- * decrement button click.
- */
- onButtonClicked_: function(sign) {
- if (!this.isValid()) {
- this.reset_();
- } else {
- var newValue = this.numberOfCopies + sign;
- this.textfield_.value = newValue;
- }
- this.updateButtonsState_();
- this.showHideCollateOption_();
-
- if (!hasPendingPreviewRequest) {
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- }
- },
-
- /**
- * Listener function to execute whenever a change occurs in |textfield_|
- * textfield.
- * @private
- */
- onTextfieldChanged_: function() {
- this.updateButtonsState_();
- this.showHideCollateOption_();
- if (!hasPendingPreviewRequest) {
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- }
- },
-
- /**
- * Adding listeners to all copies related controls. The listeners take care
- * of altering their behavior depending on |hasPendingPreviewRequest|.
- * @private
- */
- addEventListeners_: function() {
- this.textfield_.oninput = this.onTextfieldChanged_.bind(this);
- this.incrementButton_.onclick = this.onIncrementButtonClicked_.bind(this);
- this.decrementButton_.onclick = this.onDecrementButtonClicked_.bind(this);
- this.twoSidedCheckbox_.onclick = function() {
- if (!hasPendingPreviewRequest)
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- }
- document.addEventListener(customEvents.PDF_LOADED,
- this.updateButtonsState_.bind(this));
- document.addEventListener(customEvents.PRINTER_CAPABILITIES_UPDATED,
- this.onPrinterCapabilitiesUpdated_.bind(this));
- },
-
- /**
- * Executes when a |customEvents.PRINTER_CAPABILITIES_UPDATED| event occurs.
- * @private
- */
- onPrinterCapabilitiesUpdated_: function(e) {
- var duplexValue = e.printerCapabilities.printerDefaultDuplexValue;
- if (duplexValue != CopiesSettings.UNKNOWN_DUPLEX_MODE &&
- this.previousDuplexMode_ != CopiesSettings.UNKNOWN_DUPLEX_MODE) {
- duplexValue = this.previousDuplexMode_;
- }
- this.updateTwoSidedOption_(duplexValue);
- e.printerCapabilities.disableCopiesOption ?
- fadeOutOption(this.copiesOption_) :
- fadeInOption(this.copiesOption_);
- },
-
- /**
- * Listener triggered when |incrementButton_| is clicked.
- * @private
- */
- onIncrementButtonClicked_: function() {
- this.onButtonClicked_(1);
- },
-
- /**
- * Listener triggered when |decrementButton_| is clicked.
- * @private
- */
- onDecrementButtonClicked_: function() {
- this.onButtonClicked_(-1);
- },
-
- /**
- * Takes care of showing/hiding the collate option.
- * @private
- */
- showHideCollateOption_: function() {
- this.collateOption_.hidden = this.numberOfCopies <= 1;
- },
-
- /*
- * Takes care of showing/hiding the two sided option.
- * @param {number} defaultDuplexValue Specifies the default duplex value.
- * @private
- */
- updateTwoSidedOption_: function(defaultDuplexValue) {
- // On Windows, some printers don't specify their duplex values in the
- // printer schema. If the printer duplex value is UNKNOWN_DUPLEX_MODE,
- // hide the two sided option in preview tab UI.
- // Ref bug: http://crbug.com/89204
- this.twoSidedOption_.hidden =
- (defaultDuplexValue == CopiesSettings.UNKNOWN_DUPLEX_MODE);
-
- if (!this.twoSidedOption_.hidden) {
- this.twoSidedCheckbox_.checked = !!defaultDuplexValue;
- if (pageSettings.totalPageCount)
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- }
- },
-
- /**
- * Updates the state of the increment/decrement buttons based on the current
- * |textfield_| value.
- * @private
- */
- updateButtonsState_: function() {
- if (!this.isValid()) {
- this.textfield_.classList.add('invalid');
- this.incrementButton_.disabled = false;
- this.decrementButton_.disabled = false;
- fadeInElement(this.hint_);
- } else {
- this.textfield_.classList.remove('invalid');
- this.incrementButton_.disabled = this.numberOfCopies == this.maxValue_;
- this.decrementButton_.disabled = this.numberOfCopies == this.minValue_;
- fadeOutElement(this.hint_);
- }
- this.hint_.setAttribute('aria-hidden', this.isValid());
- }
- };
-
- return {
- CopiesSettings: CopiesSettings
- };
-});
diff --git a/chrome/browser/resources/print_preview/data/capabilities_holder.js b/chrome/browser/resources/print_preview/data/capabilities_holder.js
new file mode 100644
index 0000000..bb4a1aa
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/capabilities_holder.js
@@ -0,0 +1,43 @@
+// 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';
+
+ /**
+ * Mutable reference to a capabilities object.
+ * @constructor
+ */
+ function CapabilitiesHolder() {
+ /**
+ * Reference to the capabilities object.
+ * @type {print_preview.ChromiumCapabilities}
+ * @private
+ */
+ this.capabilities_ = null;
+ };
+
+ CapabilitiesHolder.prototype = {
+ /**
+ * @return {print_preview.ChromiumCapabilities} The instance held by the
+ * holder.
+ */
+ get: function() {
+ return this.capabilities_;
+ },
+
+ /**
+ * @param {!print_preview.ChromiumCapabilities} New instance to put into the
+ * holder.
+ */
+ set: function(capabilities) {
+ this.capabilities_ = capabilities;
+ }
+ };
+
+ // Export
+ return {
+ CapabilitiesHolder: CapabilitiesHolder
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/chromium_capabilities.js b/chrome/browser/resources/print_preview/data/chromium_capabilities.js
new file mode 100644
index 0000000..1cb238d
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/chromium_capabilities.js
@@ -0,0 +1,180 @@
+// 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';
+
+ /**
+ * Capabilities of a print destination not including the capabilities of the
+ * document renderer.
+ * @param {boolean} hasCopiesCapability Whether the print destination has a
+ * copies capability.
+ * @param {string} defaultCopiesStr Default string representation of the
+ * copies value.
+ * @param {boolean} hasCollateCapability Whether the print destination has
+ * collation capability.
+ * @param {boolean} defaultIsCollateEnabled Whether collate is enabled by
+ * default.
+ * @param {boolean} hasDuplexCapability Whether the print destination has
+ * duplexing capability.
+ * @param {boolean} defaultIsDuplexEnabled Whether duplexing is enabled by
+ * default.
+ * @param {boolean} hasOrientationCapability Whether the print destination has
+ * orientation capability.
+ * @param {boolean} defaultIsLandscapeEnabled Whether the document should be
+ * printed in landscape by default.
+ * @param {boolean} hasColorCapability Whether the print destination has
+ * color printing capability.
+ * @param {boolean} defaultIsColorEnabled Whether the document should be
+ * printed in color by default.
+ * @constructor
+ */
+ function ChromiumCapabilities(
+ hasCopiesCapability,
+ defaultCopiesStr,
+ hasCollateCapability,
+ defaultIsCollateEnabled,
+ hasDuplexCapability,
+ defaultIsDuplexEnabled,
+ hasOrientationCapability,
+ defaultIsLandscapeEnabled,
+ hasColorCapability,
+ defaultIsColorEnabled) {
+ /**
+ * Whether the print destination has a copies capability.
+ * @type {boolean}
+ * @private
+ */
+ this.hasCopiesCapability_ = hasCopiesCapability;
+
+ /**
+ * Default string representation of the copies value.
+ * @type {string}
+ * @private
+ */
+ this.defaultCopiesStr_ = defaultCopiesStr;
+
+ /**
+ * Whether the print destination has collation capability.
+ * @type {boolean}
+ * @private
+ */
+ this.hasCollateCapability_ = hasCollateCapability;
+
+ /**
+ * Whether collate is enabled by default.
+ * @type {boolean}
+ * @private
+ */
+ this.defaultIsCollateEnabled_ = defaultIsCollateEnabled;
+
+ /**
+ * Whether the print destination has duplexing capability.
+ * @type {boolean}
+ * @private
+ */
+ this.hasDuplexCapability_ = hasDuplexCapability;
+
+ /**
+ * Whether duplex is enabled by default.
+ * @type {boolean}
+ * @private
+ */
+ this.defaultIsDuplexEnabled_ = defaultIsDuplexEnabled;
+
+ /**
+ * Whether the print destination has orientation capability.
+ * @type {boolean}
+ * @private
+ */
+ this.hasOrientationCapability_ = hasOrientationCapability;
+
+ /**
+ * Whether the document should be printed in landscape by default.
+ * @type {boolean}
+ * @private
+ */
+ this.defaultIsLandscapeEnabled_ = defaultIsLandscapeEnabled;
+
+ /**
+ * Whether the print destination has color printing capability.
+ * @type {boolean}
+ * @private
+ */
+ this.hasColorCapability_ = hasColorCapability;
+
+ /**
+ * Whether the document should be printed in color.
+ * @type {boolean}
+ * @private
+ */
+ this.defaultIsColorEnabled_ = defaultIsColorEnabled;
+ };
+
+ ChromiumCapabilities.prototype = {
+ /** @return {boolean} Whether the destination has the copies capability. */
+ get hasCopiesCapability() {
+ return this.hasCopiesCapability_;
+ },
+
+ /** @return {string} Default number of copies in string format. */
+ get defaultCopiesStr() {
+ return this.defaultCopiesStr_;
+ },
+
+ /** @return {boolean} Whether the destination has collation capability. */
+ get hasCollateCapability() {
+ return this.hasCollateCapability_;
+ },
+
+ /** @return {boolean} Whether collation is enabled by default. */
+ get defaultIsCollateEnabled() {
+ return this.defaultIsCollateEnabled_;
+ },
+
+ /** @return {boolean} Whether the destination has the duplex capability. */
+ get hasDuplexCapability() {
+ return this.hasDuplexCapability_;
+ },
+
+ /** @return {boolean} Whether duplexing is enabled by default. */
+ get defaultIsDuplexEnabled() {
+ return this.defaultIsDuplexEnabled_;
+ },
+
+ /**
+ * @return {boolean} Whether the destination has the orientation capability.
+ */
+ get hasOrientationCapability() {
+ return this.hasOrientationCapability_;
+ },
+
+ /**
+ * @return {boolean} Whether document should be printed in landscape by
+ * default.
+ */
+ get defaultIsLandscapeEnabled() {
+ return this.defaultIsLandscapeEnabled_;
+ },
+
+ /**
+ * @return {boolean} Whether the destination has color printing capability.
+ */
+ get hasColorCapability() {
+ return this.hasColorCapability_;
+ },
+
+ /**
+ * @return {boolean} Whether document should be printed in color by default.
+ */
+ get defaultIsColorEnabled() {
+ return this.defaultIsColorEnabled_;
+ }
+ };
+
+ // Export
+ return {
+ ChromiumCapabilities: ChromiumCapabilities
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/cloud_capabilities.js b/chrome/browser/resources/print_preview/data/cloud_capabilities.js
new file mode 100644
index 0000000..7bb107f
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/cloud_capabilities.js
@@ -0,0 +1,413 @@
+// 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';
+
+ /**
+ * Capabilities of a cloud-based print destination.
+ * @param {print_preview.CollateCapability} collateCapability Print
+ * destination collate capability.
+ * @param {print_preview.ColorCapability} colorCapability Print destination
+ * color capability.
+ * @param {print_preview.CopiesCapability} copiesCapability Print destination
+ * copies capability.
+ * @param {print_preview.DuplexCapability} duplexCapability Print destination
+ * duplexing capability.
+ * @constructor
+ * @extends {print_preview.ChromiumCapabilities}
+ */
+ function CloudCapabilities(
+ collateCapability, colorCapability, copiesCapability, duplexCapability) {
+ print_preview.ChromiumCapabilities.call(
+ this,
+ !!copiesCapability,
+ '1' /*defaultCopiesStr*/,
+ !!collateCapability,
+ !!collateCapability && collateCapability.isCollateDefault,
+ !!duplexCapability,
+ !!duplexCapability && duplexCapability.isDuplexDefault,
+ true /*hasOrientationCapability*/,
+ false /*defaultIsLandscapeEnabled*/,
+ !!colorCapability,
+ !!colorCapability && colorCapability.isColorDefault);
+
+ /**
+ * Print destination collate capability.
+ * @type {print_preview.CollateCapability}
+ * @private
+ */
+ this.collateCapability_ = collateCapability;
+
+ /**
+ * Print destination color capability.
+ * @type {print_preview.ColorCapability}
+ * @private
+ */
+ this.colorCapability_ = colorCapability;
+
+ /**
+ * Print destination copies capability.
+ * @type {print_preview.CopiesCapability}
+ * @private
+ */
+ this.copiesCapability_ = copiesCapability;
+
+ /**
+ * Print destination duplexing capability.
+ * @type {print_preview.DuplexCapability}
+ * @private
+ */
+ this.duplexCapability_ = duplexCapability;
+ };
+
+ /**
+ * Enumeration of the capability formats of cloud-based print destinations.
+ * @enum {string}
+ */
+ CloudCapabilities.Format = {
+ HP: 'hp',
+ PPD: 'ppd',
+ XPS: 'xps'
+ };
+
+ CloudCapabilities.prototype = {
+ __proto__: print_preview.ChromiumCapabilities.prototype,
+
+ /**
+ * @return {print_preview.CollateCapability} The print destination's collate
+ * capability.
+ */
+ get collateCapability() {
+ return this.collateCapability_;
+ },
+
+ /**
+ * @return {print_preview.CollateCapability} The print destination's color
+ * capability.
+ */
+ get colorCapability() {
+ return this.colorCapability_;
+ },
+
+ /**
+ * @return {print_preview.CollateCapability} The print destination's copies
+ * capability.
+ */
+ get copiesCapability() {
+ return this.copiesCapability_;
+ },
+
+ /**
+ * @return {print_preview.CollateCapability} The print destination's
+ * duplexing capability.
+ */
+ get duplexCapability() {
+ return this.duplexCapability_;
+ }
+ };
+
+ /**
+ * A single print capability of a cloud-based print destination.
+ * @param {string} id Identifier of the capability.
+ * @param {print_preview.CloudCapability.Type} type Type of the capability.
+ * @constructor
+ */
+ function CloudCapability(id, type) {
+ /**
+ * Identifier of the capability.
+ * @type {string}
+ * @private
+ */
+ this.id_ = id;
+
+ /**
+ * Type of the capability.
+ * @type {print_preview.CloudCapability.Type}
+ * @private
+ */
+ this.type_ = type;
+ };
+
+ /**
+ * Enumeration of the types of cloud-based print capabilities.
+ * @enum {string}
+ */
+ CloudCapability.Type = {
+ FEATURE: 'Feature',
+ PARAMETER_DEF: 'ParameterDef'
+ };
+
+ CloudCapability.prototype = {
+ /** @return {string} Identifier of the capability. */
+ get id() {
+ return this.id_;
+ },
+
+ /** @return {print_preview.CloudCapability.Type} Type of the capability. */
+ get type() {
+ return this.type_;
+ }
+ };
+
+ /**
+ * Cloud-based collate capability.
+ * @param {string} id Identifier of the collate capability.
+ * @param {string} collateOption Identifier of the option that enables
+ * collation.
+ * @param {string} noCollateOption Identifier of the option that disables
+ * collation.
+ * @param {boolean} isCollateDefault Whether collation is enabled by default.
+ * @constructor
+ * @extends {print_preview.CloudCapability}
+ */
+ function CollateCapability(
+ id, collateOption, noCollateOption, isCollateDefault) {
+ CloudCapability.call(this, id, CloudCapability.Type.FEATURE);
+
+ /**
+ * Identifier of the option that enables collation.
+ * @type {string}
+ * @private
+ */
+ this.collateOption_ = collateOption;
+
+ /**
+ * Identifier of the option that disables collation.
+ * @type {string}
+ * @private
+ */
+ this.noCollateOption_ = noCollateOption;
+
+ /**
+ * Whether collation is enabled by default.
+ * @type {boolean}
+ * @private
+ */
+ this.isCollateDefault_ = isCollateDefault;
+ };
+
+ /**
+ * Mapping of capability formats to an identifier of the collate capability.
+ * @type {object<CloudCapabilities.Format, string>}
+ */
+ CollateCapability.Id = {};
+ CollateCapability.Id[CloudCapabilities.Format.PPD] = 'Collate';
+ CollateCapability.Id[CloudCapabilities.Format.XPS] = 'psk:DocumentCollate';
+
+ /**
+ * Regular expression that matches a collate option.
+ * @type {!RegExp}
+ * @const
+ */
+ CollateCapability.COLLATE_REGEX = /(.*:collated.*|true)/i;
+
+ /**
+ * Regular expression that matches a no-collate option.
+ * @type {!RegExp}
+ * @const
+ */
+ CollateCapability.NO_COLLATE_REGEX = /(.*:uncollated.*|false)/i;
+
+ CollateCapability.prototype = {
+ __proto__: CloudCapability.prototype,
+
+ /** @return {string} Identifier of the option that enables collation. */
+ get collateOption() {
+ return this.collateOption_;
+ },
+
+ /** @return {string} Identifier of the option that disables collation. */
+ get noCollateOption() {
+ return this.noCollateOption_;
+ },
+
+ /** @return {boolean} Whether collation is enabled by default. */
+ get isCollateDefault() {
+ return this.isCollateDefault_;
+ }
+ };
+
+ /**
+ * Cloud-based color print capability.
+ * @param {string} id Identifier of the color capability.
+ * @param {string} colorOption Identifier of the color option.
+ * @param {string} bwOption Identifier of the black-white option.
+ * @param {boolean} Whether color printing is enabled by default.
+ * @constructor
+ */
+ function ColorCapability(id, colorOption, bwOption, isColorDefault) {
+ CloudCapability.call(this, id, CloudCapability.Type.FEATURE);
+
+ /**
+ * Identifier of the color option.
+ * @type {string}
+ * @private
+ */
+ this.colorOption_ = colorOption;
+
+ /**
+ * Identifier of the black-white option.
+ * @type {string}
+ * @private
+ */
+ this.bwOption_ = bwOption;
+
+ /**
+ * Whether to print in color by default.
+ * @type {boolean}
+ * @private
+ */
+ this.isColorDefault_ = isColorDefault;
+ };
+
+ /**
+ * Mapping of capability formats to an identifier of the color capability.
+ * @type {object<CloudCapabilities.Format, string>}
+ */
+ ColorCapability.Id = {};
+ ColorCapability.Id[CloudCapabilities.Format.HP] = 'ns1:Colors';
+ ColorCapability.Id[CloudCapabilities.Format.PPD] = 'ColorModel';
+ ColorCapability.Id[CloudCapabilities.Format.XPS] = 'psk:PageOutputColor';
+
+ /**
+ * Regular expression that matches a color option.
+ * @type {!RegExp}
+ * @const
+ */
+ ColorCapability.COLOR_REGEX = /(.*color.*|.*rgb.*|.*cmy.*|true)/i;
+
+ /**
+ * Regular expression that matches a black-white option.
+ * @type {!RegExp}
+ * @const
+ */
+ ColorCapability.BW_REGEX = /(.*gray.*|.*mono.*|.*black.*|false)/i;
+
+ ColorCapability.prototype = {
+ __proto__: CloudCapability.prototype,
+
+ /** @return {string} Identifier of the color option. */
+ get colorOption() {
+ return this.colorOption_;
+ },
+
+ /** @return {string} Identifier of the black-white option. */
+ get bwOption() {
+ return this.bwOption_;
+ },
+
+ /** @return {boolean} Whether to print in color by default. */
+ get isColorDefault() {
+ return this.isColorDefault_;
+ }
+ };
+
+ /**
+ * Cloud-based copies print capability.
+ * @param {string} id Identifier of the copies capability.
+ * @constructor
+ */
+ function CopiesCapability(id) {
+ CloudCapability.call(this, id, CloudCapability.Type.PARAMETER_DEF);
+ };
+
+ CopiesCapability.prototype = {
+ __proto__: CloudCapability.prototype
+ };
+
+ /**
+ * Mapping of capability formats to an identifier of the copies capability.
+ * @type {object<CloudCapabilities.Format, string>}
+ */
+ CopiesCapability.Id = {};
+ CopiesCapability.Id[CloudCapabilities.Format.XPS] =
+ 'psk:JobCopiesAllDocuments';
+
+ /**
+ * Cloud-based duplex print capability.
+ * @param {string} id Identifier of the duplex capability.
+ * @param {string} simplexOption Identifier of the no-duplexing option.
+ * @param {string} longEdgeOption Identifier of the duplex on long edge
+ * option.
+ * @param {boolean} Whether duplexing is enabled by default.
+ * @constructor
+ */
+ function DuplexCapability(
+ id, simplexOption, longEdgeOption, isDuplexDefault) {
+ CloudCapability.call(this, id, CloudCapability.Type.FEATURE);
+
+ /**
+ * Identifier of the no-duplexing option.
+ * @type {string}
+ * @private
+ */
+ this.simplexOption_ = simplexOption;
+
+ /**
+ * Identifier of the duplex on long edge option.
+ * @type {string}
+ * @private
+ */
+ this.longEdgeOption_ = longEdgeOption;
+
+ /**
+ * Whether duplexing is enabled by default.
+ * @type {boolean}
+ * @private
+ */
+ this.isDuplexDefault_ = isDuplexDefault;
+ };
+
+ /**
+ * Mapping of capability formats to an identifier of the duplex capability.
+ * @type {object<CloudCapabilities.Format, string>}
+ */
+ DuplexCapability.Id = {};
+ DuplexCapability.Id[CloudCapabilities.Format.PPD] = 'Duplex';
+ DuplexCapability.Id[CloudCapabilities.Format.XPS] =
+ 'psk:JobDuplexAllDocumentsContiguously';
+
+ /**
+ * Regular expression that matches a no-duplexing option.
+ * @type {!RegExp}
+ * @const
+ */
+ DuplexCapability.SIMPLEX_REGEX = /(.*onesided.*|.*none.*)/i;
+
+ /**
+ * Regular expression that matches a duplex on long edge option.
+ * @type {!RegExp}
+ * @const
+ */
+ DuplexCapability.LONG_EDGE_REGEX = /(.*longedge.*|duplexNoTumble)/i;
+
+ DuplexCapability.prototype = {
+ __proto__: CloudCapability.prototype,
+
+ /** @return {string} Identifier of the no-duplexing option. */
+ get simplexOption() {
+ return this.simplexOption_;
+ },
+
+ /** @return {string} Identifier of the duplex on long edge option. */
+ get longEdgeOption() {
+ return this.longEdgeOption_;
+ },
+
+ /** @return {boolean} Whether duplexing is enabled by default. */
+ get isDuplexDefault() {
+ return this.isDuplexDefault_;
+ }
+ };
+
+ // Export
+ return {
+ CloudCapabilities: CloudCapabilities,
+ CollateCapability: CollateCapability,
+ ColorCapability: ColorCapability,
+ CopiesCapability: CopiesCapability,
+ DuplexCapability: DuplexCapability
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/cloud_parsers.js b/chrome/browser/resources/print_preview/data/cloud_parsers.js
new file mode 100644
index 0000000..965e881
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/cloud_parsers.js
@@ -0,0 +1,207 @@
+// 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('cloudprint', function() {
+ 'use strict';
+
+ /** Namespace which contains a method to parse cloud destinations directly. */
+ function CloudDestinationParser() {};
+
+ /**
+ * Enumeration of cloud destination field names.
+ * @enum {string}
+ * @private
+ */
+ CloudDestinationParser.Field_ = {
+ CAPABILITIES: 'capabilities',
+ DISPLAY_NAME: 'displayName',
+ FORMAT: 'capsFormat',
+ ID: 'id',
+ TAGS: 'tags'
+ };
+
+ /**
+ * Special tag that denotes whether the destination has been recently used.
+ * @type {string}
+ * @private
+ */
+ CloudDestinationParser.RECENT_TAG_ = '^recent';
+
+ /**
+ * Parses a destination from JSON from a Google Cloud Print search or printer
+ * response.
+ * @param {object} json Object that represents a Google Cloud Print search or
+ * printer response.
+ * @return {!print_preview.Destination} Parsed destination.
+ */
+ CloudDestinationParser.parse = function(json) {
+ if (!json.hasOwnProperty(CloudDestinationParser.Field_.ID) ||
+ !json.hasOwnProperty(CloudDestinationParser.Field_.DISPLAY_NAME)) {
+ throw Error('Cloud destination does not have an ID or a display name');
+ }
+ var isRecent = arrayContains(
+ json[CloudDestinationParser.Field_.TAGS] || [],
+ CloudDestinationParser.RECENT_TAG_);
+ var cloudDest = new print_preview.Destination(
+ json[CloudDestinationParser.Field_.ID],
+ json[CloudDestinationParser.Field_.DISPLAY_NAME],
+ isRecent,
+ false /*isLocal*/,
+ json[CloudDestinationParser.Field_.TAGS] || []);
+ if (json.hasOwnProperty(CloudDestinationParser.Field_.CAPABILITIES) &&
+ json.hasOwnProperty(CloudDestinationParser.Field_.FORMAT)) {
+ cloudDest.capabilities = CloudCapabilitiesParser.parse(
+ json[CloudDestinationParser.Field_.FORMAT],
+ json[CloudDestinationParser.Field_.CAPABILITIES]);
+ }
+ return cloudDest;
+ };
+
+ /**
+ * Namespace which contains a method to parse a cloud destination's print
+ * capabilities.
+ */
+ function CloudCapabilitiesParser() {};
+
+ /**
+ * Enumeration of cloud destination print capabilities field names.
+ * @enum {string}
+ * @private
+ */
+ CloudCapabilitiesParser.Field_ = {
+ CAP_ID: 'name',
+ DEFAULT: 'default',
+ IS_DEFAULT: 'default',
+ OPTIONS: 'options',
+ OPTION_ID: 'name'
+ };
+
+ /**
+ * Parses print capabilities from an object in a given capabilities format.
+ * @param {print_preview.CloudCapabilities.Format} capsFormat Format of the
+ * printer capabilities.
+ * @param {object} json Object representing the cloud capabilities.
+ * @return {!print_preview.CloudCapabilities} Parsed print capabilities.
+ */
+ CloudCapabilitiesParser.parse = function(capsFormat, json) {
+ var colorCapability = null;
+ var duplexCapability = null;
+ var copiesCapability = null;
+ var collateCapability = null;
+ for (var cap, i = 0; cap = json[i]; i++) {
+ var capId = cap[CloudCapabilitiesParser.Field_.CAP_ID];
+ if (capId == print_preview.CollateCapability.Id[capsFormat]) {
+ collateCapability = CloudCapabilitiesParser.parseCollate(capId, cap);
+ } else if (capId == print_preview.ColorCapability.Id[capsFormat]) {
+ colorCapability = CloudCapabilitiesParser.parseColor(capId, cap);
+ } else if (capId == print_preview.CopiesCapability.Id[capsFormat]) {
+ copiesCapability = new print_preview.CopiesCapability(capId);
+ } else if (capId == print_preview.DuplexCapability.Id[capsFormat]) {
+ duplexCapability = CloudCapabilitiesParser.parseDuplex(capId, cap);
+ }
+ }
+ return new print_preview.CloudCapabilities(
+ collateCapability, colorCapability, copiesCapability, duplexCapability);
+ };
+
+ /**
+ * Parses a collate capability from the given object.
+ * @param {string} capId Native ID of the given capability object.
+ * @param {object} Object that represents the collate capability.
+ * @return {print_preview.CollateCapability} Parsed collate capability or
+ * {@code null} if the given capability object was not a valid collate
+ * capability.
+ */
+ CloudCapabilitiesParser.parseCollate = function(capId, cap) {
+ var options = cap[CloudCapabilitiesParser.Field_.OPTIONS];
+ var collateOption = null;
+ var noCollateOption = null;
+ var isCollateDefault = false;
+ for (var option, i = 0; option = options[i]; i++) {
+ var optionId = option[CloudCapabilitiesParser.Field_.OPTION_ID];
+ if (!collateOption &&
+ print_preview.CollateCapability.COLLATE_REGEX.test(optionId)) {
+ collateOption = optionId;
+ isCollateDefault = !!option[CloudCapabilitiesParser.Field_.DEFAULT];
+ } else if (!noCollateOption &&
+ print_preview.CollateCapability.NO_COLLATE_REGEX.test(optionId)) {
+ noCollateOption = optionId;
+ }
+ }
+ if (!collateOption || !noCollateOption) {
+ return null;
+ }
+ return new print_preview.CollateCapability(
+ capId, collateOption, noCollateOption, isCollateDefault);
+ };
+
+ /**
+ * Parses a color capability from the given object.
+ * @param {string} capId Native ID of the given capability object.
+ * @param {object} Object that represents the color capability.
+ * @return {print_preview.ColorCapability} Parsed color capability or
+ * {@code null} if the given capability object was not a valid color
+ * capability.
+ */
+ CloudCapabilitiesParser.parseColor = function(capId, cap) {
+ var options = cap[CloudCapabilitiesParser.Field_.OPTIONS];
+ var colorOption = null;
+ var bwOption = null;
+ var isColorDefault = false;
+ for (var option, i = 0; option = options[i]; i++) {
+ var optionId = option[CloudCapabilitiesParser.Field_.OPTION_ID];
+ if (!colorOption &&
+ print_preview.ColorCapability.COLOR_REGEX.test(optionId)) {
+ colorOption = optionId;
+ isColorDefault = !!option[CloudCapabilitiesParser.Field_.DEFAULT];
+ } else if (!bwOption &&
+ print_preview.ColorCapability.BW_REGEX.test(optionId)) {
+ bwOption = optionId;
+ }
+ }
+ if (!colorOption || !bwOption) {
+ return null;
+ }
+ return new print_preview.ColorCapability(
+ capId, colorOption, bwOption, isColorDefault);
+ };
+
+ /**
+ * Parses a duplex capability from the given object.
+ * @param {string} capId Native ID of the given capability object.
+ * @param {object} Object that represents the duplex capability.
+ * @return {print_preview.DuplexCapability} Parsed duplex capability or
+ * {@code null} if the given capability object was not a valid duplex
+ * capability.
+ */
+ CloudCapabilitiesParser.parseDuplex = function(capId, cap) {
+ var options = cap[CloudCapabilitiesParser.Field_.OPTIONS];
+ var simplexOption = null;
+ var longEdgeOption = null;
+ var isDuplexDefault = false;
+ for (var option, i = 0; option = options[i]; i++) {
+ var optionId = option[CloudCapabilitiesParser.Field_.OPTION_ID];
+ if (!simplexOption &&
+ print_preview.DuplexCapability.SIMPLEX_REGEX.test(optionId)) {
+ simplexOption = optionId;
+ } else if (!longEdgeOption &&
+ print_preview.DuplexCapability.LONG_EDGE_REGEX.test(optionId)) {
+ longEdgeOption = optionId;
+ isDuplexDefault = !!option[CloudCapabilitiesParser.Field_.DEFAULT];
+ }
+ }
+ if (!simplexOption || !longEdgeOption) {
+ return null;
+ }
+ return new print_preview.DuplexCapability(
+ capId, simplexOption, longEdgeOption, isDuplexDefault);
+ };
+
+ // Export
+ return {
+ CloudCapabilitiesParser: CloudCapabilitiesParser,
+ CloudDestinationParser: CloudDestinationParser
+ };
+});
+
diff --git a/chrome/browser/resources/print_preview/data/coordinate2d.js b/chrome/browser/resources/print_preview/data/coordinate2d.js
new file mode 100644
index 0000000..4b10af6
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/coordinate2d.js
@@ -0,0 +1,76 @@
+// 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';
+
+ /**
+ * Immutable two dimensional point in space. The units of the dimensions are
+ * undefined.
+ * @param {number} x X-dimension of the point.
+ * @param {number} y Y-dimension of the point.
+ * @constructor
+ */
+ function Coordinate2d(x, y) {
+ /**
+ * X-dimension of the point.
+ * @type {number}
+ * @private
+ */
+ this.x_ = x;
+
+ /**
+ * Y-dimension of the point.
+ * @type {number}
+ * @private
+ */
+ this.y_ = y;
+ };
+
+ Coordinate2d.prototype = {
+ /** @return {number} X-dimension of the point. */
+ get x() {
+ return this.x_;
+ },
+
+ /** @return {number} Y-dimension of the point. */
+ get y() {
+ return this.y_;
+ },
+
+ /**
+ * @param {number} x Amount to translate in the X dimension.
+ * @param {number} y Amount to translate in the Y dimension.
+ * @return {!print_preview.Coordinate2d} A new two-dimensional point
+ * translated along the X and Y dimensions.
+ */
+ translate: function(x, y) {
+ return new Coordinate2d(this.x_ + x, this.y_ + y);
+ },
+
+ /**
+ * @param {number} factor Amount to scale the X and Y dimensions.
+ * @return {!print_preview.Coordinate2d} A new two-dimensional point scaled
+ * by the given factor.
+ */
+ scale: function(factor) {
+ return new Coordinate2d(this.x_ * factor, this.y_ * factor);
+ },
+
+ /**
+ * @param {print_preview.Coordinate2d} other The point to compare against.
+ * @return {boolean} Whether another point is equal to this one.
+ */
+ equals: function(other) {
+ return other != null &&
+ this.x_ == other.x_ &&
+ this.y_ == other.y_;
+ }
+ };
+
+ // Export
+ return {
+ Coordinate2d: Coordinate2d
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
new file mode 100644
index 0000000..01a9491
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -0,0 +1,188 @@
+// 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';
+
+ /**
+ * Print destination data object that holds data for both local and cloud
+ * destinations.
+ * @param {string} id ID of the destination.
+ * @param {string} displayName Display name of the destination.
+ * @param {boolean} isRecent Whether the destination has been used recently.
+ * @param {boolean} isLocal Whether the destination is local or cloud-based.
+ * @param {Array.<string>=} opt_tags Tags associated with the destination.
+ * @constructor
+ */
+ function Destination(id, displayName, isRecent, isLocal, opt_tags) {
+ /**
+ * ID of the destination.
+ * @type {string}
+ * @private
+ */
+ this.id_ = id;
+
+ /**
+ * Display name of the destination.
+ * @type {string}
+ * @private
+ */
+ this.displayName_ = displayName;
+
+ /**
+ * Whether the destination has been used recently.
+ * @type {boolean}
+ * @private
+ */
+ this.isRecent_ = isRecent;
+
+ /**
+ * Whether the destination is local or cloud-based.
+ * @type {boolean}
+ * @private
+ */
+ this.isLocal_ = isLocal;
+
+ /**
+ * Tags associated with the destination.
+ * @type {!Array.<string>}
+ * @private
+ */
+ this.tags_ = opt_tags || [];
+
+ /**
+ * Print capabilities of the destination.
+ * @type {print_preview.ChromiumCapabilities}
+ * @private
+ */
+ this.capabilities_ = null;
+
+ /**
+ * Cache of destination location fetched from tags.
+ * @type {string}
+ * @private
+ */
+ this.location_ = null;
+ };
+
+ /**
+ * Prefix of the location destination tag.
+ * @type {string}
+ * @const
+ */
+ Destination.LOCATION_TAG_PREFIX = '__cp__printer-location=';
+
+ /**
+ * Enumeration of Google-promoted destination IDs.
+ * @enum {string}
+ */
+ Destination.GooglePromotedId = {
+ DOCS: '__google__docs',
+ SAVE_AS_PDF: 'Save as PDF',
+ PRINT_WITH_CLOUD_PRINT: 'printWithCloudPrint'
+ };
+
+ Destination.prototype = {
+ /** @return {string} ID of the destination. */
+ get id() {
+ return this.id_;
+ },
+
+ /** @return {string} Display name of the destination. */
+ get displayName() {
+ return this.displayName_;
+ },
+
+ /** @return {boolean} Whether the destination has been used recently. */
+ get isRecent() {
+ return this.isRecent_;
+ },
+
+ /**
+ * @param {boolean} isRecent Whether the destination has been used recently.
+ */
+ set isRecent(isRecent) {
+ this.isRecent_ = isRecent;
+ },
+
+ /** @return {boolean} Whether the destination is local or cloud-based. */
+ get isLocal() {
+ return this.isLocal_;
+ },
+
+ /** @return {boolean} Whether the destination is promoted by Google. */
+ get isGooglePromoted() {
+ for (var key in Destination.GooglePromotedId) {
+ if (Destination.GooglePromotedId[key] == this.id_) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * @return {boolean} Whether the destination is the "Print with Cloud Print"
+ * destination.
+ */
+ get isPrintWithCloudPrint() {
+ return this.id_ == Destination.GooglePromotedId.PRINT_WITH_CLOUD_PRINT;
+ },
+
+ /**
+ * @return {string} The location of the destination, or an empty string if
+ * the location is unknown.
+ */
+ get location() {
+ if (this.location_ == null) {
+ for (var tag, i = 0; tag = this.tags_[i]; i++) {
+ if (tag.indexOf(Destination.LOCATION_TAG_PREFIX) == 0) {
+ this.location_ = tag.substring(
+ Destination.LOCATION_TAG_PREFIX.length);
+ }
+ }
+ if (this.location_ == null) {
+ this.location_ = '';
+ }
+ }
+ return this.location_;
+ },
+
+ /** @return {!Array.<string>} Tags associated with the destination. */
+ get tags() {
+ return this.tags_.slice(0);
+ },
+
+ /**
+ * @return {print_preview.ChromiumCapabilities} Print capabilities of the
+ * destination.
+ */
+ get capabilities() {
+ return this.capabilities_;
+ },
+
+ /**
+ * @param {!print_preview.ChromiumCapabilities} capabilities Print
+ * capabilities of the destination.
+ */
+ set capabilities(capabilities) {
+ this.capabilities_ = capabilities;
+ },
+
+ /**
+ * Matches a query against the destination.
+ * @param {string} query Query to match against the destination.
+ * @return {boolean} {@code true} if the query matches this destination,
+ * {@code false} otherwise.
+ */
+ matches: function(query) {
+ return this.displayName_.toLowerCase().indexOf(
+ query.toLowerCase().trim()) != -1;
+ }
+ };
+
+ // Export
+ return {
+ Destination: Destination
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
new file mode 100644
index 0000000..69f766a
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -0,0 +1,192 @@
+// 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';
+
+ /**
+ * A data store that stores destinations and dispatches events when the data
+ * store changes.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+ function DestinationStore() {
+ cr.EventTarget.call(this);
+
+ /**
+ * Internal backing store for the data store.
+ * @type {!Array.<print_preview.Destination>}
+ * @private
+ */
+ this.destinations_ = [];
+
+ /**
+ * Currently selected destination.
+ * @type {print_preview.Destination}
+ * @private
+ */
+ this.selectedDestination_ = null;
+
+ /**
+ * Initial destination ID used to auto-select the first inserted destination
+ * that matches. If {@code null}, the first destination inserted into the
+ * store will be selected.
+ * @type {?string}
+ * @private
+ */
+ this.initialDestinationId_ = null;
+
+ /**
+ * Whether the destination store will auto select the destination that
+ * matches the initial destination.
+ * @type {boolean}
+ * @private
+ */
+ this.isInAutoSelectMode_ = false;
+ };
+
+ /**
+ * Event types dispatched by the data store.
+ * @enum {string}
+ */
+ DestinationStore.EventType = {
+ DESTINATIONS_INSERTED:
+ 'print_preview.DestinationStore.DESTINATIONS_INSERTED',
+ DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT'
+ };
+
+ DestinationStore.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ /**
+ * @return {!Array.<!print_preview.Destination>} List of destinations in
+ * the store.
+ */
+ get destinations() {
+ return this.destinations_.slice(0);
+ },
+
+ /**
+ * @return {print_preview.Destination} The currently selected destination or
+ * {@code null} if none is selected.
+ */
+ get selectedDestination() {
+ return this.selectedDestination_;
+ },
+
+ /**
+ * Sets the initially selected destination. If any inserted destinations
+ * match this ID, that destination will be automatically selected. This
+ * occurs only once for every time this setter is called or if the store is
+ * cleared.
+ * @param {string} ID of the destination that should be selected
+ * automatically when added to the store.
+ */
+ setInitialDestinationId: function(initialDestinationId) {
+ this.initialDestinationId_ = initialDestinationId;
+ this.isInAutoSelectMode_ = true;
+ if (this.initialDestinationId_ == null && this.destinations_.length > 0) {
+ this.selectDestination(this.destinations_[0]);
+ } else if (this.initialDestinationId_ != null) {
+ for (var dest, i = 0; dest = this.destinations_[i]; i++) {
+ if (dest.id == initialDestinationId) {
+ this.selectDestination(dest);
+ break;
+ }
+ }
+ }
+ },
+
+ /** @param {!print_preview.Destination} Destination to select. */
+ selectDestination: function(destination) {
+ this.selectedDestination_ = destination;
+ this.selectedDestination_.isRecent = true;
+ this.isInAutoSelectMode_ = false;
+ cr.dispatchSimpleEvent(
+ this, DestinationStore.EventType.DESTINATION_SELECT);
+ },
+
+ /**
+ * Inserts a print destination to the data store and dispatches a
+ * DESTINATIONS_INSERTED event. If the destination matches the initial
+ * destination ID, then the destination will be automatically selected.
+ * @param {!print_preview.Destination} destination Print destination to
+ * insert.
+ */
+ insertDestination: function(destination) {
+ this.destinations_.push(destination);
+ cr.dispatchSimpleEvent(
+ this, DestinationStore.EventType.DESTINATIONS_INSERTED);
+ if (this.isInAutoSelectMode_) {
+ if (this.initialDestinationId_ == null) {
+ this.selectDestination(destination);
+ } else {
+ if (destination.id == this.initialDestinationId_) {
+ this.selectDestination(destination);
+ }
+ }
+ }
+ },
+
+ /**
+ * Inserts multiple print destinations to the data store and dispatches one
+ * DESTINATIONS_INSERTED event. If any of the destinations match the initial
+ * destination ID, then that destination will be automatically selected.
+ * @param {!Array.<print_preview.Destination>} destinations Print
+ * destinations to insert.
+ */
+ insertDestinations: function(destinations) {
+ this.destinations_ = this.destinations_.concat(destinations);
+ cr.dispatchSimpleEvent(
+ this, DestinationStore.EventType.DESTINATIONS_INSERTED);
+ if (this.isInAutoSelectMode_) {
+ if (this.initialDestinationId_ == null && destinations.length > 0) {
+ this.selectDestination(destinations[0]);
+ } else if (this.initialDestinationId_ != null) {
+ for (var dest, i = 0; dest = destinations[i]; i++) {
+ if (dest.id == this.initialDestinationId_) {
+ this.selectDestination(dest);
+ break;
+ }
+ }
+ }
+ }
+ },
+
+ /**
+ * Updates an existing print destination with capabilities information. If
+ * the destination doesn't already exist, it will be added.
+ * @param {!print_preview.Destination} destination Destination to update.
+ * @return {!print_preview.Destination} The existing destination that was
+ * updated.
+ */
+ updateDestination: function(destination) {
+ var existingDestination = null;
+ for (var d, i = 0; d = this.destinations_[i]; i++) {
+ if (destination.id == d.id) {
+ existingDestination = d;
+ break;
+ }
+ }
+ if (existingDestination) {
+ existingDestination.capabilities = destination.capabilities;
+ return existingDestination;
+ } else {
+ this.insertDestination(destination);
+ }
+ },
+
+ /** Clears all print destinations. */
+ clear: function() {
+ this.destinations_ = [];
+ this.selectedDestination_ = null;
+ this.isInAutoSelectMode_ = true;
+ }
+ };
+
+ // Export
+ return {
+ DestinationStore: DestinationStore
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/document_info.js b/chrome/browser/resources/print_preview/data/document_info.js
new file mode 100644
index 0000000..dd2fdcd
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/document_info.js
@@ -0,0 +1,55 @@
+// 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';
+
+ /**
+ * Object which contains information related to the document to print.
+ * @constructor
+ */
+ function DocumentInfo() {
+ /**
+ * Whether the document to print is modifiable (i.e. can be reflowed).
+ * @type {boolean}
+ */
+ this.isModifiable = true;
+
+ /**
+ * Number of pages in the document to print.
+ * @type {number}
+ */
+ this.pageCount = 1;
+
+ /**
+ * Size of the pages of the document in points.
+ * @type {!print_preview.Size}
+ */
+ this.pageSize = new print_preview.Size(0, 0);
+
+ /**
+ * Printable area of the document in points.
+ * @type {!print_preview.PrintableArea}
+ */
+ this.printableArea = new print_preview.PrintableArea(
+ new print_preview.Coordinate2d(0, 0), new print_preview.Size(0, 0));
+
+ /**
+ * Whether the document is styled by CSS media styles.
+ * @type {boolean}
+ */
+ this.hasCssMediaStyles = false;
+
+ /**
+ * Margins of the document in points.
+ * @type {print_preview.Margins}
+ */
+ this.margins = null;
+ };
+
+ // Export
+ return {
+ DocumentInfo: DocumentInfo
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/local_parsers.js b/chrome/browser/resources/print_preview/data/local_parsers.js
new file mode 100644
index 0000000..af58290
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/local_parsers.js
@@ -0,0 +1,70 @@
+// 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';
+
+ /** Namespace that contains a method to parse local print destinations. */
+ function LocalDestinationParser() {};
+
+ /**
+ * Parses a local print destination.
+ * @param {object} destinationInfo Information describing a local print
+ * destination.
+ * @return {!print_preview.Destination} Parsed local print destination.
+ */
+ LocalDestinationParser.parse = function(destinationInfo) {
+ return new print_preview.Destination(
+ destinationInfo.deviceName,
+ destinationInfo.printerName,
+ false /*isRecent*/,
+ true /*isLocal*/);
+ };
+
+ /** Namespace that contains a method to parse local print capabilities. */
+ function LocalCapabilitiesParser() {};
+
+ /**
+ * Parses local print capabilities.
+ * @param {object} settingsInfo Object that describes local print
+ * capabilities.
+ * @return {!print_preview.ChromiumCapabilities} Parsed local print
+ * capabilities.
+ */
+ LocalCapabilitiesParser.parse = function(settingsInfo) {
+ var hasColorCapability = false;
+ var defaultIsColorEnabled = false;
+ if (hasColorCapability = !settingsInfo['disableColorOption']) {
+ defaultIsColorEnabled = settingsInfo['setColorAsDefault'];
+ }
+
+ var hasDuplexCapability = false;
+ var defaultIsDuplexEnabled = false;
+ if (hasDuplexCapability =
+ settingsInfo['printerDefaultDuplexValue'] !=
+ print_preview.NativeLayer.DuplexMode.UNKNOWN_DUPLEX_MODE) {
+ defaultIsDuplexEnabled =
+ settingsInfo['printerDefaultDuplexValue'] ==
+ print_preview.NativeLayer.DuplexMode.LONG_EDGE;
+ }
+
+ return new print_preview.ChromiumCapabilities(
+ !settingsInfo['disableCopiesOption'] /*hasCopiesCapability*/,
+ '1' /*defaultCopiesStr*/,
+ true /*hasCollateCapability*/,
+ true /*defaultIsCollateEnabled*/,
+ hasDuplexCapability,
+ defaultIsDuplexEnabled,
+ !settingsInfo['disableLandscapeOption'] /*hasOrientationCapability*/,
+ false /*defaultIsLandscapeEnabled*/,
+ hasColorCapability,
+ defaultIsColorEnabled);
+ };
+
+ // Export
+ return {
+ LocalCapabilitiesParser: LocalCapabilitiesParser,
+ LocalDestinationParser: LocalDestinationParser
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/margins.js b/chrome/browser/resources/print_preview/data/margins.js
new file mode 100644
index 0000000..cf6a6f8
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/margins.js
@@ -0,0 +1,86 @@
+// 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 Margins object that holds four margin values in points.
+ * @param {number} top The top margin in pts.
+ * @param {number} right The right margin in pts.
+ * @param {number} bottom The bottom margin in pts.
+ * @param {number} left The left margin in pts.
+ * @constructor
+ */
+ function Margins(top, right, bottom, left) {
+ /**
+ * Backing store for the margin values in points.
+ * @type {Object.<
+ * print_preview.ticket_items.CustomMargins.Orientation,
+ * number>}
+ * @private
+ */
+ this.value_ = {};
+ this.value_[print_preview.ticket_items.CustomMargins.Orientation.TOP] = top;
+ this.value_[print_preview.ticket_items.CustomMargins.Orientation.RIGHT] =
+ right;
+ this.value_[print_preview.ticket_items.CustomMargins.Orientation.BOTTOM] =
+ bottom;
+ this.value_[print_preview.ticket_items.CustomMargins.Orientation.LEFT] =
+ left;
+ };
+
+ Margins.prototype = {
+ /**
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Specifies the margin value to get.
+ * @return {number} Value of the margin of the given orientation.
+ */
+ get: function(orientation) {
+ return this.value_[orientation];
+ },
+
+ /**
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Specifies the margin to set.
+ * @param {number} value Updated value of the margin in points to modify.
+ * @return {!print_preview.Margins} A new copy of |this| with the
+ * modification made to the specified margin.
+ */
+ set: function(orientation, value) {
+ var newValue = {};
+ for (var o in this.value_) {
+ newValue[o] = this.value_[o];
+ }
+ newValue[orientation] = value;
+ return new Margins(
+ newValue[print_preview.ticket_items.CustomMargins.Orientation.TOP],
+ newValue[print_preview.ticket_items.CustomMargins.Orientation.RIGHT],
+ newValue[print_preview.ticket_items.CustomMargins.Orientation.BOTTOM],
+ newValue[print_preview.ticket_items.CustomMargins.Orientation.LEFT]);
+ },
+
+ /**
+ * @param {print_preview.Margins} other The other margins object to compare
+ * against.
+ * @return {boolean} Whether this margins object is equal to another.
+ */
+ equals: function(other) {
+ if (other == null) {
+ return false;
+ }
+ for (var orientation in this.value_) {
+ if (this.value_[orientation] != other.value_[orientation]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ // Export
+ return {
+ Margins: Margins
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/measurement_system.js b/chrome/browser/resources/print_preview/data/measurement_system.js
new file mode 100644
index 0000000..ccee0d9a
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/measurement_system.js
@@ -0,0 +1,159 @@
+// 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';
+
+ /**
+ * Measurement system of the print preview. Used to parse and serialize point
+ * measurements into the system's local units (e.g. millimeters, inches).
+ * @param {string} thousandsDelimeter Delimeter between thousands digits.
+ * @param {string} decimalDelimeter Delimeter between integers and decimals.
+ * @param {print_preview.MeasurementSystem.UnitType} unitType Measurement unit
+ * type of the system.
+ * @constructor
+ */
+ function MeasurementSystem(thousandsDelimeter, decimalDelimeter, unitType) {
+ this.thousandsDelimeter_ = thousandsDelimeter || ',';
+ this.decimalDelimeter_ = decimalDelimeter || '.';
+ this.unitType_ = unitType;
+ };
+
+ /**
+ * Parses |numberFormat| and extracts the symbols used for the thousands point
+ * and decimal point.
+ * @param {string} numberFormat The formatted version of the number 12345678.
+ * @return {!Array.<string>} The extracted symbols in the order
+ * [thousandsSymbol, decimalSymbol]. For example,
+ * parseNumberFormat("123,456.78") returns [",", "."].
+ */
+ MeasurementSystem.parseNumberFormat = function(numberFormat) {
+ if (!numberFormat) {
+ return [',', '.'];
+ }
+ var regex = /^(\d+)(\W?)(\d+)(\W?)(\d+)$/;
+ var matches = numberFormat.match(regex) || ['', '', ',', '', '.'];
+ return [matches[2], matches[4]];
+ };
+
+ /**
+ * Enumeration of measurement unit types.
+ * @enum {number}
+ */
+ MeasurementSystem.UnitType = {
+ METRIC: 0, // millimeters
+ IMPERIAL: 1 // inches
+ };
+
+ /**
+ * Maximum resolution of local unit values.
+ * @type {Object.<print_preview.MeasurementSystem.UnitType, number>}
+ * @private
+ */
+ MeasurementSystem.Precision_ = {};
+ MeasurementSystem.Precision_[MeasurementSystem.UnitType.METRIC] = 0.5;
+ MeasurementSystem.Precision_[MeasurementSystem.UnitType.IMPERIAL] = 0.01;
+
+ /**
+ * Maximum number of decimal places to keep for local unit.
+ * @type {Object.<print_preview.MeasurementSystem.UnitType, number>}
+ * @private
+ */
+ MeasurementSystem.DecimalPlaces_ = {};
+ MeasurementSystem.DecimalPlaces_[MeasurementSystem.UnitType.METRIC] = 1;
+ MeasurementSystem.DecimalPlaces_[MeasurementSystem.UnitType.IMPERIAL] = 2;
+
+ /**
+ * Number of points per inch.
+ * @type {number}
+ * @const
+ * @private
+ */
+ MeasurementSystem.PTS_PER_INCH_ = 72.0;
+
+ /**
+ * Number of points per millimeter.
+ * @type {number}
+ * @const
+ * @private
+ */
+ MeasurementSystem.PTS_PER_MM_ = MeasurementSystem.PTS_PER_INCH_ / 25.4;
+
+ MeasurementSystem.prototype = {
+ /** @return {string} The unit type symbol of the measurement system. */
+ get unitSymbol() {
+ if (this.unitType_ == MeasurementSystem.UnitType.METRIC) {
+ return 'mm';
+ } else if (this.unitType_ == MeasurementSystem.UnitType.IMPERIAL) {
+ return '"';
+ } else {
+ throw Error('Unit type not supported: ' + this.unitType_);
+ }
+ },
+
+ /**
+ * @return {string} The thousands delimeter character of the measurement
+ * system.
+ */
+ get thousandsDelimeter() {
+ return this.thousandsDelimeter_;
+ },
+
+ /**
+ * @return {string} The decimal delimeter character of the measurement
+ * system.
+ */
+ get decimalDelimeter() {
+ return this.decimalDelimeter_;
+ },
+
+ setSystem: function(thousandsDelimeter, decimalDelimeter, unitType) {
+ this.thousandsDelimeter_ = thousandsDelimeter;
+ this.decimalDelimeter_ = decimalDelimeter;
+ this.unitType_ = unitType;
+ },
+
+ /**
+ * Rounds a value in the local system's units to the appropriate precision.
+ * @param {number} value Value to round.
+ * @return {number} Rounded value.
+ */
+ roundValue: function(value) {
+ var precision = MeasurementSystem.Precision_[this.unitType_];
+ var roundedValue = Math.round(value / precision) * precision;
+ // Truncate
+ return roundedValue.toFixed(
+ MeasurementSystem.DecimalPlaces_[this.unitType_]);
+ },
+
+ /**
+ * @param {number} pts Value in points to convert to local units.
+ * @return {number} Value in local units.
+ */
+ convertFromPoints: function(pts) {
+ if (this.unitType_ == MeasurementSystem.UnitType.METRIC) {
+ return pts / MeasurementSystem.PTS_PER_MM_;
+ } else {
+ return pts / MeasurementSystem.PTS_PER_INCH_;
+ }
+ },
+
+ /**
+ * @param {number} Value in local units to convert to points.
+ * @return {number} Value in points.
+ */
+ convertToPoints: function(localUnits) {
+ if (this.unitType_ == MeasurementSystem.UnitType.METRIC) {
+ return localUnits * MeasurementSystem.PTS_PER_MM_;
+ } else {
+ return localUnits * MeasurementSystem.PTS_PER_INCH_;
+ }
+ }
+ };
+
+ // Export
+ return {
+ MeasurementSystem: MeasurementSystem
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/measurement_system_unittest.gtestjs b/chrome/browser/resources/print_preview/data/measurement_system_unittest.gtestjs
new file mode 100644
index 0000000..ed246c8
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/measurement_system_unittest.gtestjs
@@ -0,0 +1,68 @@
+// 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.
+
+/**
+ * Test fixture for the MeasurementSystem.
+ * @constructor
+ * @extends {testing.Test}
+ */
+function MeasurementSystemUnitTest() {
+ testing.Test.call(this);
+}
+
+MeasurementSystemUnitTest.prototype = {
+ __proto__: testing.Test.prototype,
+
+ extraLibraries: [
+ '../../shared/js/cr.js',
+ '../print_preview_utils.js',
+ 'measurement_system.js'
+ ]
+};
+
+TEST_F('MeasurementSystemUnitTest', 'parseNumberFormat', function() {
+ assertTrue(areArraysEqual(
+ ['.', ','],
+ print_preview.MeasurementSystem.parseNumberFormat('123.456,78')));
+ assertTrue(areArraysEqual(
+ ['.', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat('123.456.78')));
+ assertTrue(areArraysEqual(
+ [',', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat('123,456.78')));
+ assertTrue(areArraysEqual(
+ [',', ','],
+ print_preview.MeasurementSystem.parseNumberFormat('123,456,78')));
+ assertTrue(areArraysEqual(
+ [' ', ','],
+ print_preview.MeasurementSystem.parseNumberFormat('123 456,78')));
+ assertTrue(areArraysEqual(
+ [' ', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat('123 456.78')));
+ assertTrue(areArraysEqual(
+ [' ', ' '],
+ print_preview.MeasurementSystem.parseNumberFormat('123 456 78')));
+ assertTrue(areArraysEqual(
+ ['', ''],
+ print_preview.MeasurementSystem.parseNumberFormat('123')));
+
+ assertTrue(areArraysEqual(
+ [',', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat('abcdef')));
+ assertTrue(areArraysEqual(
+ [',', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat(null)));
+ assertTrue(areArraysEqual(
+ [',', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat(undefined)));
+ assertTrue(areArraysEqual(
+ [',', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat('')));
+ assertTrue(areArraysEqual(
+ [',', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat('1')));
+ assertTrue(areArraysEqual(
+ [',', '.'],
+ print_preview.MeasurementSystem.parseNumberFormat('12')));
+});
diff --git a/chrome/browser/resources/print_preview/data/page_number_set.js b/chrome/browser/resources/print_preview/data/page_number_set.js
new file mode 100644
index 0000000..cccb6bf
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/page_number_set.js
@@ -0,0 +1,105 @@
+// 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';
+
+ /**
+ * An immutable ordered set of page numbers.
+ * @param {!Array.<number>} pageNumberList A list of page numbers to include
+ * in the set.
+ * @constructor
+ */
+ function PageNumberSet(pageNumberList) {
+ /**
+ * Internal data store for the page number set.
+ * @type {!Array.<number>}
+ * @private
+ */
+ this.pageNumberSet_ = pageListToPageSet(pageNumberList);
+ };
+
+ /**
+ * @param {string} pageRangeStr String form of a page range. I.e. '2,3,4-5'.
+ * If string is empty, all page numbers will be in the page number set.
+ * @param {number} totalPageCount Total number of pages in the original
+ * document.
+ * @return {print_preview.PageNumberSet} Page number set parsed from the
+ * given page range string and total page count. Null returned if
+ * the given page range string is invalid.
+ */
+ PageNumberSet.parse = function(pageRangeStr, totalPageCount) {
+ if (pageRangeStr == '') {
+ var pageNumberList = [];
+ for (var i = 0; i < totalPageCount; i++) {
+ pageNumberList.push(i + 1);
+ }
+ return new PageNumberSet(pageNumberList);
+ } else {
+ return isPageRangeTextValid(pageRangeStr, totalPageCount) ?
+ new PageNumberSet(
+ pageRangeTextToPageList(pageRangeStr, totalPageCount)) : null;
+ }
+ };
+
+ PageNumberSet.prototype = {
+ /** @return {number} The number of page numbers in the set. */
+ get size() {
+ return this.pageNumberSet_.length;
+ },
+
+ /**
+ * @param {number} index 0-based index of the page number to get.
+ * @return {number} Page number at the given index.
+ */
+ getPageNumberAt: function(index) {
+ return this.pageNumberSet_[index];
+ },
+
+ /**
+ * @param {number} 1-based page number to check for.
+ * @return {boolean} Whether the given page number is in the page range.
+ */
+ hasPageNumber: function(pageNumber) {
+ return arrayContains(this.pageNumberSet_, pageNumber);
+ },
+
+ /**
+ * @param {number} 1-based number of the page to get index of.
+ * @return {number} 0-based index of the given page number with respect to
+ * all of the pages in the page range.
+ */
+ getPageNumberIndex: function(pageNumber) {
+ return this.pageNumberSet_.indexOf(pageNumber);
+ },
+
+ /**
+ * @return {!Array.<object.<{from: number, to: number}>>} A list of page
+ * ranges suitable for use in the native layer.
+ */
+ getPageRanges: function() {
+ return pageSetToPageRanges(this.pageNumberSet_);
+ },
+
+ /** @return {!Array.<number>} Array representation of the set. */
+ asArray: function() {
+ return this.pageNumberSet_.slice(0);
+ },
+
+ /**
+ * @param {print_preview.PageNumberSet} other Page number set to compare
+ * against.
+ * @return {boolean} Whether another page number set is equal to this one.
+ */
+ equals: function(other) {
+ return other == null ?
+ false : areArraysEqual(this.pageNumberSet_, other.pageNumberSet_);
+ }
+ };
+
+ // Export
+ return {
+ PageNumberSet: PageNumberSet
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/print_ticket_store.js b/chrome/browser/resources/print_preview/data/print_ticket_store.js
new file mode 100644
index 0000000..e200798
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/print_ticket_store.js
@@ -0,0 +1,629 @@
+// 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';
+
+ // TODO(rltoscano): Maybe clear print ticket when destination changes. Or
+ // better yet, carry over any print ticket state that is possible. I.e. if
+ // destination changes, the new destination might not support duplex anymore,
+ // so we should clear the ticket's isDuplexEnabled state.
+
+ /**
+ * Storage of the print ticket and document statistics. Dispatches events when
+ * the contents of the print ticket or document statistics change. Also
+ * handles validation of the print ticket against destination capabilities and
+ * against the document.
+ * @param {!print_preview.DestinationStore} destinationStore Used to
+ * understand which printer is selected.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+ function PrintTicketStore(destinationStore) {
+ cr.EventTarget.call(this);
+
+ /**
+ * Destination store used to understand which printer is selected.
+ * @type {!print_preview.DestinationStore}
+ * @private
+ */
+ this.destinationStore_ = destinationStore;
+
+ // Create the document info with some initial settings. Actual
+ // page-related information won't be set until preview generation occurs,
+ // so we'll use some defaults until then. This way, the print ticket store
+ // will be valid even if no preview can be generated.
+ var initialPageSize = new print_preview.Size(612, 792); // 8.5"x11"
+
+ /**
+ * Information about the document to print.
+ * @type {!print_preview.DocumentInfo}
+ * @private
+ */
+ this.documentInfo_ = new print_preview.DocumentInfo();
+ this.documentInfo_.isModifiable = true;
+ this.documentInfo_.pageCount = 1;
+ this.documentInfo_.pageSize = initialPageSize;
+ this.documentInfo_.printableArea = new print_preview.PrintableArea(
+ new print_preview.Coordinate2d(0, 0), initialPageSize);
+
+ /**
+ * Printing capabilities of Chromium and the currently selected destination.
+ * @type {!print_preview.CapabilitiesHolder}
+ * @private
+ */
+ this.capabilitiesHolder_ = new print_preview.CapabilitiesHolder();
+
+ /**
+ * Current measurement system. Used to work with margin measurements.
+ * @type {!print_preview.MeasurementSystem}
+ * @private
+ */
+ this.measurementSystem_ = new print_preview.MeasurementSystem(
+ ',', '.', print_preview.MeasurementSystem.UnitType.IMPERIAL);
+
+ /**
+ * Collate ticket item.
+ * @type {!print_preview.ticket_items.Collate}
+ * @private
+ */
+ this.collate_ =
+ new print_preview.ticket_items.Collate(this.capabilitiesHolder_);
+
+ /**
+ * Color ticket item.
+ * @type {!print_preview.ticket_items.Color}
+ * @private
+ */
+ this.color_ = new print_preview.ticket_items.Color(
+ this.capabilitiesHolder_, this.destinationStore_);
+
+ /**
+ * Copies ticket item.
+ * @type {!print_preview.ticket_items.Copies}
+ * @private
+ */
+ this.copies_ =
+ new print_preview.ticket_items.Copies(this.capabilitiesHolder_);
+
+ /**
+ * Duplex ticket item.
+ * @type {!print_preview.ticket_items.Duplex}
+ * @private
+ */
+ this.duplex_ =
+ new print_preview.ticket_items.Duplex(this.capabilitiesHolder_);
+
+ /**
+ * Landscape ticket item.
+ * @type {!print_preview.ticket_items.Landscape}
+ * @private
+ */
+ this.landscape_ = new print_preview.ticket_items.Landscape(
+ this.capabilitiesHolder_, this.documentInfo_);
+
+ /**
+ * Page range ticket item.
+ * @type {!print_preview.ticket_items.PageRange}
+ * @private
+ */
+ this.pageRange_ =
+ new print_preview.ticket_items.PageRange(this.documentInfo_);
+
+ /**
+ * Margins type ticket item.
+ * @type {!print_preview.ticket_items.MarginsType}
+ * @private
+ */
+ this.marginsType_ =
+ new print_preview.ticket_items.MarginsType(this.documentInfo_);
+
+ /**
+ * Custom margins ticket item.
+ * @type {!print_preview.ticket_items.CustomMargins}
+ * @private
+ */
+ this.customMargins_ = new print_preview.ticket_items.CustomMargins(
+ this.documentInfo_, this.measurementSystem_);
+
+ /**
+ * Header-footer ticket item.
+ * @type {!print_preview.ticket_items.HeaderFooter}
+ * @private
+ */
+ this.headerFooter_ = new print_preview.ticket_items.HeaderFooter(
+ this.documentInfo_, this.marginsType_, this.customMargins_);
+
+ /**
+ * Fit-to-page ticket item.
+ * @type {!print_preview.ticket_items.FitToPage}
+ * @private
+ */
+ this.fitToPage_ = new print_preview.ticket_items.FitToPage(
+ this.documentInfo_, this.destinationStore_);
+ };
+
+ /**
+ * Event types dispatched by the print ticket store.
+ * @enum {string}
+ */
+ PrintTicketStore.EventType = {
+ CAPABILITIES_CHANGE: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE',
+ DOCUMENT_CHANGE: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE',
+ INITIALIZE: 'print_preview.PrintTicketStore.INITIALIZE',
+ TICKET_CHANGE: 'print_preview.PrintTicketStore.TICKET_CHANGE'
+ };
+
+ PrintTicketStore.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ /** @return {boolean} Whether the document is modifiable. */
+ get isDocumentModifiable() {
+ return this.documentInfo_.isModifiable;
+ },
+
+ /** @return {number} Number of pages in the document. */
+ get pageCount() {
+ return this.documentInfo_.pageCount;
+ },
+
+ /**
+ * @param {number} pageCount New number of pages in the document.
+ * Dispatches a DOCUMENT_CHANGE event if the value changes.
+ */
+ updatePageCount: function(pageCount) {
+ if (this.documentInfo_.pageCount != pageCount) {
+ this.documentInfo_.pageCount = pageCount;
+ cr.dispatchSimpleEvent(
+ this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
+ }
+ },
+
+ /**
+ * @return {!print_preview.PrintableArea} Printable area of the document in
+ * points.
+ */
+ get printableArea() {
+ return this.documentInfo_.printableArea;
+ },
+
+ /** @return {!print_preview.Size} Size of the document in points. */
+ get pageSize() {
+ return this.documentInfo_.pageSize;
+ },
+
+ /**
+ * Updates a subset of fields of the print document relating to the format
+ * of the page.
+ * @param {!print_preview.PrintableArea} printableArea New printable area of
+ * the document in points. Dispatches a DOCUMENT_CHANGE event if the
+ * value changes.
+ * @param {!print_preview.Size} pageSize New size of the document in points.
+ * Dispatches a DOCUMENT_CHANGE event if the value changes.
+ * @param {boolean} documentHasCssMediaStyles Whether the document is styled
+ * with CSS media styles.
+ * @param {!print_preview.Margins} margins Document margins in points.
+ */
+ updateDocumentPageInfo: function(
+ printableArea, pageSize, documentHasCssMediaStyles, margins) {
+ if (!this.documentInfo_.printableArea.equals(printableArea) ||
+ !this.documentInfo_.pageSize.equals(pageSize) ||
+ this.documentInfo_.hasCssMediaStyles != documentHasCssMediaStyles ||
+ this.documentInfo_.margins == null ||
+ !this.documentInfo_.margins.equals(margins)) {
+ this.documentInfo_.printableArea = printableArea;
+ this.documentInfo_.pageSize = pageSize;
+ this.documentInfo_.hasCssMediaStyles = documentHasCssMediaStyles;
+ this.documentInfo_.margins = margins;
+ cr.dispatchSimpleEvent(
+ this, PrintTicketStore.EventType.DOCUMENT_CHANGE);
+ }
+ },
+
+ /**
+ * @return {!print_preview.MeasurementSystem} Measurement system of the
+ * local system.
+ */
+ get measurementSystem() {
+ return this.measurementSystem_;
+ },
+
+ /**
+ * @return {print_preview.Margins} Document margins of the currently
+ * generated preview.
+ */
+ getDocumentMargins: function() {
+ return this.documentInfo_.margins;
+ },
+
+ /**
+ * Initializes the print ticket store. Dispatches an INITIALIZE event.
+ * @param {boolean} isDocumentModifiable Whether the document to print is
+ * modifiable (i.e. can be re-flowed by Chromium).
+ * @param {?boolean} isDuplexEnabled Previous duplex setting.
+ * @param {?boolean} isHeaderFooterEnabled Previous header-footer setting.
+ * @param {?print_preview.ticket_items.MarginsType.Value} marginsType
+ * Previous margins type.
+ * @param {print_preview.Margins} customMargins Previous custom margins.
+ * @param {string} thousandsDelimeter Delimeter of the thousands place.
+ * @param {string} decimalDelimeter Delimeter of the decimal point.
+ * @param {print_preview.MeasurementSystem.UnitType} unitType Type of unit
+ * of the local measurement system.
+ */
+ initialize: function(
+ isDocumentModifiable,
+ isDuplexEnabled,
+ isHeaderFooterEnabled,
+ marginsType,
+ customMargins,
+ thousandsDelimeter,
+ decimalDelimeter,
+ unitType) {
+
+ this.documentInfo_.isModifiable = isDocumentModifiable;
+ this.measurementSystem_.setSystem(
+ thousandsDelimeter, decimalDelimeter, unitType);
+
+ // Initialize ticket with user's previous values.
+ this.duplex_.updateValue(isDuplexEnabled);
+ this.headerFooter_.updateValue(isHeaderFooterEnabled);
+ if (marginsType != null) {
+ this.marginsType_.updateValue(marginsType);
+ }
+ if (customMargins != null) {
+ this.customMargins_.updateValue(customMargins);
+ }
+ },
+
+ /**
+ * Updates the capabilities of the destination the print ticket is for.
+ * Dispatches a CAPABILITIES_CHANGE event.
+ * @param {!print_preview.ChromiumCapabilities} caps New capabilities.
+ */
+ updateDestinationCapabilities: function(caps) {
+ var isFirstUpdate = this.capabilitiesHolder_.get() == null;
+ this.capabilitiesHolder_.set(caps);
+ if (isFirstUpdate) {
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.INITIALIZE);
+ } else {
+ this.customMargins_.updateValue(null);
+ if (this.marginsType_.getValue() ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ this.marginsType_.updateValue(
+ print_preview.ticket_items.MarginsType.Value.DEFAULT);
+ }
+ cr.dispatchSimpleEvent(
+ this, PrintTicketStore.EventType.CAPABILITIES_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether the ticket store has the copies capability. */
+ hasCopiesCapability: function() {
+ return this.copies_.isCapabilityAvailable();
+ },
+
+ /**
+ * @return {boolean} Whether the string representation of the copies value
+ * currently in the ticket store is valid.
+ */
+ isCopiesValid: function() {
+ return this.copies_.isValid();
+ },
+
+ isCopiesValidForValue: function(value) {
+ return this.copies_.wouldValueBeValid(value);
+ },
+
+ /** @return {number} Number of copies to print. */
+ getCopies: function() {
+ return this.copies_.getValueAsNumber();
+ },
+
+ /**
+ * @return {string} String representation of the number of copies to print.
+ */
+ getCopiesStr: function() {
+ return this.copies_.getValue();
+ },
+
+ /**
+ * Updates the string representation of the number of copies to print.
+ * Dispatches a TICKET_CHANGE event if the string value has changed.
+ * @param {string} New string representation of the number of copies to
+ * print.
+ */
+ updateCopies: function(copies) {
+ if (this.copies_.getValue() != copies) {
+ this.copies_.updateValue(copies);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether the ticket store has a collate capability. */
+ hasCollateCapability: function() {
+ return this.collate_.isCapabilityAvailable();
+ },
+
+ /** @return {boolean} Whether collate is enabled. */
+ isCollateEnabled: function() {
+ return this.collate_.getValue();
+ },
+
+ /**
+ * Updates whether collate is enabled. Dispatches a TICKET_CHANGE event if
+ * collate has changed.
+ * @param {boolean} isCollateEnabled Whether collate is enabled.
+ */
+ updateCollate: function(isCollateEnabled) {
+ if (this.collate_.getValue() != isCollateEnabled) {
+ this.collate_.updateValue(isCollateEnabled);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /**
+ * @return {boolean} Whether the ticket store has color printing capability.
+ */
+ hasColorCapability: function() {
+ return this.color_.isCapabilityAvailable();
+ },
+
+ /** @return {boolean} Whether color printing is enabled. */
+ isColorEnabled: function() {
+ return this.color_.getValue();
+ },
+
+ /**
+ * Updates whether color printing is enabled. Dispatches a TICKET_CHANGE if
+ * color has changed.
+ * @param {boolean} isColorEnabled Whether the color printing is enabled.
+ */
+ updateColor: function(isColorEnabled) {
+ if (this.color_.getValue() != isColorEnabled) {
+ this.color_.updateValue(isColorEnabled);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether the header-footer capability is available. */
+ hasHeaderFooterCapability: function() {
+ return this.headerFooter_.isCapabilityAvailable();
+ },
+
+ /** @return {boolean} Whether the header-footer setting is enabled. */
+ isHeaderFooterEnabled: function() {
+ return this.headerFooter_.getValue();
+ },
+
+ /**
+ * Updates the whether the header-footer setting is enabled. Dispatches a
+ * TICKET_CHANGE event if the setting changed.
+ * @param {boolean} isHeaderFooterEnabled Whether the header-footer setting
+ * is enabled.
+ */
+ updateHeaderFooter: function(isHeaderFooterEnabled) {
+ if (this.headerFooter_.getValue() != isHeaderFooterEnabled) {
+ this.headerFooter_.updateValue(isHeaderFooterEnabled);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /**
+ * @return {boolean} Whether the page orientation capability is available.
+ */
+ hasOrientationCapability: function() {
+ return this.landscape_.isCapabilityAvailable();
+ },
+
+ /**
+ * @return {boolean} Whether the document should be printed in landscape.
+ */
+ isLandscapeEnabled: function() {
+ return this.landscape_.getValue();
+ },
+
+ /**
+ * Updates whether the document should be printed in landscape. Dispatches
+ * a TICKET_CHANGE event if the setting changes.
+ * @param {boolean} isLandscapeEnabled Whether the document should be
+ * printed in landscape.
+ */
+ updateOrientation: function(isLandscapeEnabled) {
+ if (this.landscape_.getValue() != isLandscapeEnabled) {
+ this.landscape_.updateValue(isLandscapeEnabled);
+ // Reset the user set margins.
+ this.marginsType_.updateValue(
+ print_preview.ticket_items.MarginsType.Value.DEFAULT);
+ this.customMargins_.updateValue(null);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether the duplexing capability is available. */
+ hasDuplexCapability: function() {
+ return this.duplex_.isCapabilityAvailable();
+ },
+
+ /** @return {boolean} Whether the document should be printed in duplex. */
+ isDuplexEnabled: function() {
+ return this.duplex_.getValue();
+ },
+
+ /**
+ * Updates the duplexing setting. Dispatches a TICKET_CHANGE event if the
+ * value changes.
+ * @param {boolean} isDuplexEnabled Whether the document should be printed
+ * in duplex.
+ */
+ updateDuplex: function(isDuplexEnabled) {
+ if (this.duplex_.getValue() != isDuplexEnabled) {
+ this.duplex_.updateValue(isDuplexEnabled);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether the margins capability is available. */
+ hasMarginsCapability: function() {
+ return this.marginsType_.isCapabilityAvailable();
+ },
+
+ /**
+ * @return {print_preview.ticket_items.MarginsType.Value} Type of predefined
+ * margins.
+ */
+ getMarginsType: function() {
+ return this.marginsType_.getValue();
+ },
+
+ /**
+ * Updates the type of predefined margins. Dispatches a TICKET_CHANGE event
+ * if the margins type changes.
+ * @param {print_preview.ticket_items.MarginsType.Value} marginsType Type of
+ * predefined margins.
+ */
+ updateMarginsType: function(marginsType) {
+ if (this.marginsType_.getValue() != marginsType) {
+ this.marginsType_.updateValue(marginsType);
+ if (marginsType ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ // If CUSTOM, set the value of the custom margins so that it won't be
+ // overridden by the default value.
+ this.customMargins_.updateValue(this.customMargins_.getValue());
+ }
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether all of the custom margins are valid. */
+ isCustomMarginsValid: function() {
+ return this.customMargins_.isValid();
+ },
+
+ /**
+ * @return {!print_preview.Margins} Custom margins of the document in
+ * points.
+ */
+ getCustomMargins: function() {
+ return this.customMargins_.getValue();
+ },
+
+ /**
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Specifies the margin to get the maximum value for.
+ * @return {number} Maximum value in points of the specified margin.
+ */
+ getCustomMarginMax: function(orientation) {
+ return this.customMargins_.getMarginMax(orientation);
+ },
+
+ /**
+ * Updates the custom margins of the document. Dispatches a TICKET_CHANGE
+ * event if the margins have changed.
+ * @param {!print_preview.Margins} margins New document page margins in
+ * points.
+ */
+ updateCustomMargins: function(margins) {
+ if (!this.isCustomMarginsValid() ||
+ !margins.equals(this.getCustomMargins())) {
+ this.customMargins_.updateValue(margins);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /**
+ * Updates a single custom margin's value in points.
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Specifies the margin to update.
+ * @param {number} value Updated margin in points.
+ */
+ updateCustomMargin: function(orientation, value) {
+ if (this.customMargins_.getValue().get(orientation) != value) {
+ this.customMargins_.updateMargin(orientation, value);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether the page range capability is available. */
+ hasPageRangeCapability: function() {
+ return this.pageRange_.isCapabilityAvailable();
+ },
+
+ /**
+ * @return {boolean} Whether the current page range string is defines a
+ * valid page number set.
+ */
+ isPageRangeValid: function() {
+ return this.pageRange_.isValid();
+ },
+
+ /** @return {string} String representation of the page range. */
+ getPageRangeStr: function() {
+ return this.pageRange_.getValue();
+ },
+
+ /**
+ * @return {!print_preview.PageNumberSet} Page number set specified by the
+ * string representation of the page range string.
+ */
+ getPageNumberSet: function() {
+ return this.pageRange_.getPageNumberSet();
+ },
+
+ /**
+ * Updates the page range string. Dispatches a TICKET_CHANGE if the string
+ * changed.
+ * @param {string} pageRangeStr New page range string.
+ */
+ updatePageRange: function(pageRangeStr) {
+ if (this.pageRange_.getValue() != pageRangeStr) {
+ this.pageRange_.updateValue(pageRangeStr);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /** @return {boolean} Whether the fit-to-page capability is available. */
+ hasFitToPageCapability: function() {
+ return this.fitToPage_.isCapabilityAvailable();
+ },
+
+ /** @return {boolean} Whether the fit-to-page capability is enabled. */
+ isFitToPageEnabled: function() {
+ return this.fitToPage_.getValue();
+ },
+
+ /**
+ * @param {boolean} isFitToPageEnabled Whether to enable the fit-to-page
+ * capability.
+ */
+ updateFitToPage: function(isFitToPageEnabled) {
+ if (this.fitToPage_.getValue() != isFitToPageEnabled) {
+ this.fitToPage_.updateValue(isFitToPageEnabled);
+ cr.dispatchSimpleEvent(this, PrintTicketStore.EventType.TICKET_CHANGE);
+ }
+ },
+
+ /**
+ * @return {boolean} {@code true} if the stored print ticket is valid,
+ * {@code false} otherwise.
+ */
+ isTicketValid: function() {
+ return this.isTicketValidForPreview() &&
+ (!this.hasPageRangeCapability() || this.isPageRangeValid());
+ },
+
+ /** @return {boolean} Whether the ticket is valid for preview generation. */
+ isTicketValidForPreview: function() {
+ return (!this.hasCopiesCapability() || this.isCopiesValid()) &&
+ (!this.hasMarginsCapability() ||
+ this.getMarginsType() !=
+ print_preview.ticket_items.MarginsType.Value.CUSTOM ||
+ this.isCustomMarginsValid());
+ }
+ };
+
+ // Export
+ return {
+ PrintTicketStore: PrintTicketStore
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/printable_area.js b/chrome/browser/resources/print_preview/data/printable_area.js
new file mode 100644
index 0000000..4dd4955
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/printable_area.js
@@ -0,0 +1,64 @@
+// 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';
+
+ /**
+ * Object describing the printable area of a page in the document.
+ * @param {!print_preview.Coordinate2d} origin Top left corner of the
+ * printable area of the document.
+ * @param {!print_preview.Size} size Size of the printable area of the
+ * document.
+ * @constructor
+ */
+ function PrintableArea(origin, size) {
+ /**
+ * Top left corner of the printable area of the document.
+ * @type {!print_preview.Coordinate2d}
+ * @private
+ */
+ this.origin_ = origin;
+
+ /**
+ * Size of the printable area of the document.
+ * @type {!print_preview.Size}
+ * @private
+ */
+ this.size_ = size;
+ };
+
+ PrintableArea.prototype = {
+ /**
+ * @return {!print_preview.Coordinate2d} Top left corner of the printable
+ * area of the document.
+ */
+ get origin() {
+ return this.origin_;
+ },
+
+ /**
+ * @return {!print_preview.Size} Size of the printable area of the document.
+ */
+ get size() {
+ return this.size_;
+ },
+
+ /**
+ * @param {print_preview.PrintableArea} other Other printable area to check
+ * for equality.
+ * @return {boolean} Whether another printable area is equal to this one.
+ */
+ equals: function(other) {
+ return other != null &&
+ this.origin_.equals(other.origin_) &&
+ this.size_.equals(other.size_);
+ }
+ };
+
+ // Export
+ return {
+ PrintableArea: PrintableArea
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/size.js b/chrome/browser/resources/print_preview/data/size.js
new file mode 100644
index 0000000..7b43418
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/size.js
@@ -0,0 +1,56 @@
+// 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';
+
+ /**
+ * Immutable two-dimensional size.
+ * @param {number} width Width of the size.
+ * @param {number} height Height of the size.
+ * @constructor
+ */
+ function Size(width, height) {
+ /**
+ * Width of the size.
+ * @type {number}
+ * @private
+ */
+ this.width_ = width;
+
+ /**
+ * Height of the size.
+ * @type {number}
+ * @private
+ */
+ this.height_ = height;
+ };
+
+ Size.prototype = {
+ /** @return {number} Width of the size. */
+ get width() {
+ return this.width_;
+ },
+
+ /** @return {number} Height of the size. */
+ get height() {
+ return this.height_;
+ },
+
+ /**
+ * @param {print_preview.Size} other Other size object to compare against.
+ * @return {boolean} Whether this size object is equal to another.
+ */
+ equals: function(other) {
+ return other != null &&
+ this.width_ == other.width_ &&
+ this.height_ == other.height_;
+ }
+ };
+
+ // Export
+ return {
+ Size: Size
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/collate.js b/chrome/browser/resources/print_preview/data/ticket_items/collate.js
new file mode 100644
index 0000000..10ddcf1
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/collate.js
@@ -0,0 +1,57 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Collate ticket item whose value is a {@code boolean} that indicates whether
+ * collation is enabled.
+ * @param {!print_preview.CapabilitiesHolder} capabilitiesHolder Capabilities
+ * holder used to determine the default collate value and if the collate
+ * capability is available.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function Collate(capabilitiesHolder) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Capabilities holder used to determine the default collate value and if
+ * the collate capability is available.
+ * @type {!print_preview.CapabilitiesHolder}
+ * @private
+ */
+ this.capabilitiesHolder_ = capabilitiesHolder;
+ };
+
+ Collate.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return this.capabilitiesHolder_.get().hasCollateCapability;
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return this.capabilitiesHolder_.get().defaultIsCollateEnabled;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return false;
+ }
+ };
+
+ // Export
+ return {
+ Collate: Collate
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/color.js b/chrome/browser/resources/print_preview/data/ticket_items/color.js
new file mode 100644
index 0000000..b03d407
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/color.js
@@ -0,0 +1,71 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Color ticket item whose value is a {@code boolean} that indicates whether
+ * the document should be printed in color.
+ * @param {!print_preview.CapabilitiesHolder} capabilitiesHolder Capabilities
+ * holder used to determine the default color value and if the color
+ * capability is available.
+ * @param {!print_preview.DestinationStore} destinationStore Used to determine
+ * whether color printing should be available.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function Color(capabilitiesHolder, destinationStore) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Capabilities holder used to determine the default color value and if the
+ * color capability is available.
+ * @type {!print_preview.CapabilitiesHolder}
+ * @private
+ */
+ this.capabilitiesHolder_ = capabilitiesHolder;
+
+ /**
+ * Used to determine whether color printing should be available.
+ * @type {!print_preview.DestinationStore}
+ * @private
+ */
+ this.destinationStore_ = destinationStore;
+ };
+
+ Color.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return this.capabilitiesHolder_.get().hasColorCapability &&
+ (!this.destinationStore_.selectedDestination ||
+ this.destinationStore_.selectedDestination.id !=
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF);
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return this.capabilitiesHolder_.get().defaultIsColorEnabled;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return this.destinationStore_.selectedDestination &&
+ this.destinationStore_.selectedDestination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
+ }
+ };
+
+ // Export
+ return {
+ Color: Color
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/copies.js b/chrome/browser/resources/print_preview/data/ticket_items/copies.js
new file mode 100644
index 0000000..7cd1620
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/copies.js
@@ -0,0 +1,70 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Copies ticket item whose value is a {@code string} that indicates how many
+ * copies of the document should be printed. The ticket item is backed by a
+ * string since the user can textually input the copies value.
+ * @param {!print_preview.CapabilitiesHolder} capabilitiesHolder Capabilities
+ * holder used to determine the default number of copies and if the copies
+ * capability is available.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function Copies(capabilitiesHolder) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Capabilities holder used to determine the default number of copies and if
+ * the copies capability is available.
+ * @type {!print_preview.CapabilitiesHolder}
+ * @private
+ */
+ this.capabilitiesHolder_ = capabilitiesHolder;
+ };
+
+ Copies.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ if (/[^\d]+/.test(value)) {
+ return false;
+ }
+ var copies = parseInt(value);
+ if (copies > 999 || copies < 1) {
+ return false;
+ }
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return this.capabilitiesHolder_.get().hasCopiesCapability;
+ },
+
+ /** @return {number} The number of copies indicated by the ticket item. */
+ getValueAsNumber: function() {
+ return parseInt(this.getValue());
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return this.capabilitiesHolder_.get().defaultCopiesStr;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return '1';
+ }
+ };
+
+ // Export
+ return {
+ Copies: Copies
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js b/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js
new file mode 100644
index 0000000..774e35b
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js
@@ -0,0 +1,171 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Custom page margins ticket item whose value is a
+ * {@code print_preview.Margins}.
+ * @param {!print_preview.DocumentInfo} documentInfo Information about the
+ * document to print.
+ * @param {!print_preview.MeasurementSystem} measurementSystem Used to convert
+ * from string input into measurements in points.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function CustomMargins(documentInfo, measurementSystem) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Information about the document to print.
+ * @type {!print_preview.DocumentInfo}
+ * @private
+ */
+ this.documentInfo_ = documentInfo;
+
+ /**
+ * Used to convert from string input to measurements in points.
+ * @type {!print_preview.MeasurementSystem}
+ * @private
+ */
+ this.measurementSystem_ = measurementSystem;
+ };
+
+ /**
+ * Enumeration of the orientations of margins.
+ * @enum {string}
+ */
+ CustomMargins.Orientation = {
+ TOP: 'top',
+ RIGHT: 'right',
+ BOTTOM: 'bottom',
+ LEFT: 'left'
+ };
+
+ /**
+ * Mapping of a margin orientation to its opposite.
+ * @type {object.<CustomMargins.Orientation, CustomMargins.Orientation>}
+ * @private
+ */
+ CustomMargins.OppositeOrientation_ = {};
+ CustomMargins.OppositeOrientation_[CustomMargins.Orientation.TOP] =
+ CustomMargins.Orientation.BOTTOM;
+ CustomMargins.OppositeOrientation_[CustomMargins.Orientation.RIGHT] =
+ CustomMargins.Orientation.LEFT;
+ CustomMargins.OppositeOrientation_[CustomMargins.Orientation.BOTTOM] =
+ CustomMargins.Orientation.TOP;
+ CustomMargins.OppositeOrientation_[CustomMargins.Orientation.LEFT] =
+ CustomMargins.Orientation.RIGHT;
+
+ /**
+ * Minimum distance in points that two margins can be separated by.
+ * @type {number}
+ * @const
+ * @private
+ */
+ CustomMargins.MINIMUM_MARGINS_DISTANCE_ = 72; // 1 inch.
+
+ CustomMargins.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ var margins = /** @type {!print_preview.Margins} */ (value);
+ for (var key in CustomMargins.Orientation) {
+ var o = CustomMargins.Orientation[key];
+ var max = this.getMarginMax_(
+ o, margins.get(CustomMargins.OppositeOrientation_[o]));
+ if (margins.get(o) > max || margins.get(o) < 0) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return this.documentInfo_.isModifiable;
+ },
+
+ /**
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Specifies the margin to get the maximum value for.
+ * @return {number} Maximum value in points of the specified margin.
+ */
+ getMarginMax: function(orientation) {
+ var oppositeOrient = CustomMargins.OppositeOrientation_[orientation];
+ var margins = /** @type {!print_preview.Margins} */ (this.getValue());
+ return this.getMarginMax_(orientation, margins.get(oppositeOrient));
+ },
+
+ /** @override */
+ updateValue: function(value) {
+ var margins = /** @type {!InputMargins} */ (value);
+ if (margins != null) {
+ margins = new print_preview.Margins(
+ Math.round(margins.get(CustomMargins.Orientation.TOP)),
+ Math.round(margins.get(CustomMargins.Orientation.RIGHT)),
+ Math.round(margins.get(CustomMargins.Orientation.BOTTOM)),
+ Math.round(margins.get(CustomMargins.Orientation.LEFT)));
+ }
+ print_preview.ticket_items.TicketItem.prototype.updateValue.call(
+ this, margins);
+ },
+
+ /**
+ * Updates the specified margin in points while keeping the value within
+ * a maximum and minimum.
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Specifies the margin to update.
+ * @param {number} value Updated margin value in points.
+ */
+ updateMargin: function(orientation, value) {
+ var margins = /** @type {!print_preview.Margins} */ (this.getValue());
+ var oppositeOrientation = CustomMargins.OppositeOrientation_[orientation];
+ var max =
+ this.getMarginMax_(orientation, margins.get(oppositeOrientation));
+ value = Math.max(0, Math.min(max, value));
+ this.updateValue(margins.set(orientation, value));
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return this.documentInfo_.margins ||
+ new print_preview.Margins(72, 72, 72, 72);
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return this.documentInfo_.margins ||
+ new print_preview.Margins(72, 72, 72, 72);
+ },
+
+ /**
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Specifies which margin to get the maximum value of.
+ * @param {number} oppositeMargin Value of the margin in points
+ * opposite the specified margin.
+ * @return {number} Maximum value in points of the specified margin.
+ * @private
+ */
+ getMarginMax_: function(orientation, oppositeMargin) {
+ var max;
+ if (orientation == CustomMargins.Orientation.TOP ||
+ orientation == CustomMargins.Orientation.BOTTOM) {
+ max = this.documentInfo_.pageSize.height - oppositeMargin -
+ CustomMargins.MINIMUM_MARGINS_DISTANCE_;
+ } else {
+ max = this.documentInfo_.pageSize.width - oppositeMargin -
+ CustomMargins.MINIMUM_MARGINS_DISTANCE_;
+ }
+ return Math.round(max);
+ }
+ };
+
+ // Export
+ return {
+ CustomMargins: CustomMargins
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/duplex.js b/chrome/browser/resources/print_preview/data/ticket_items/duplex.js
new file mode 100644
index 0000000..c482982
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/duplex.js
@@ -0,0 +1,57 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Duplex ticket item whose value is a {@code boolean} that indicates whether
+ * the document should be duplex printed.
+ * @param {!print_preview.CapabilitiesHolder} capabilitiesHolder Capabilities
+ * holder used to determine the default duplex value and if duplexing
+ * is available.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function Duplex(capabilitiesHolder) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Capabilities holder used to determine the default duplex value and if
+ * duplexing is available.
+ * @type {!print_preview.CapabilitiesHolder}
+ * @private
+ */
+ this.capabilitiesHolder_ = capabilitiesHolder;
+ };
+
+ Duplex.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return this.capabilitiesHolder_.get().hasDuplexCapability;
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return this.capabilitiesHolder_.get().defaultIsDuplexEnabled;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return false;
+ }
+ };
+
+ // Export
+ return {
+ Duplex: Duplex
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/fit_to_page.js b/chrome/browser/resources/print_preview/data/ticket_items/fit_to_page.js
new file mode 100644
index 0000000..40d4a75
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/fit_to_page.js
@@ -0,0 +1,69 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Fit-to-page ticket item whose value is a {@code boolean} that indicates
+ * whether to scale the document to fit the page.
+ * @param {!print_preview.DocumentInfo} documentInfo Information about the
+ * document to print.
+ * @param {!print_preview.DestinationStore} destinationStore Used to determine
+ * whether fit to page should be available.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function FitToPage(documentInfo, destinationStore) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Information about the document to print.
+ * @type {!print_preview.DocumentInfo}
+ * @private
+ */
+ this.documentInfo_ = documentInfo;
+
+ /**
+ * Used to determine whether fit to page should be available.
+ * @type {!print_preview.DestinationStore}
+ * @private
+ */
+ this.destinationStore_ = destinationStore;
+ };
+
+ FitToPage.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return !this.documentInfo_.isModifiable &&
+ (!this.destinationStore_.selectedDestination ||
+ this.destinationStore_.selectedDestination.id !=
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF);
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return true;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return this.destinationStore_.selectedDestination &&
+ this.destinationStore_.selectedDestination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
+ }
+ };
+
+ // Export
+ return {
+ FitToPage: FitToPage
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js b/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js
new file mode 100644
index 0000000..db8e6ff
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/header_footer.js
@@ -0,0 +1,95 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Header-footer ticket item whose value is a {@code boolean} that indicates
+ * whether the document should be printed with headers and footers.
+ * @param {!print_preview.DocumentInfo} documentInfo Information about the
+ * document to print.
+ * @param {!print_preview.ticket_items.MarginsType} marginsType Ticket item
+ * that stores which predefined margins to print with.
+ * @param {!print_preview.ticket_items.CustomMargins} customMargins Ticket
+ * item that stores custom margin values.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function HeaderFooter(documentInfo, marginsType, customMargins) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Information about the document to print.
+ * @type {!print_preview.DocumentInfo}
+ * @private
+ */
+ this.documentInfo_ = documentInfo;
+
+ /**
+ * Ticket item that stores which predefined margins to print with.
+ * @type {!print_preview.ticket_items.MarginsType}
+ * @private
+ */
+ this.marginsType_ = marginsType;
+
+ /**
+ * Ticket item that stores custom margin values.
+ * @type {!print_preview.ticket_items.CustomMargins}
+ * @private
+ */
+ this.customMargins_ = customMargins;
+ };
+
+ HeaderFooter.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ if (!this.documentInfo_.isModifiable) {
+ return false;
+ } else if (this.marginsType_.getValue() ==
+ print_preview.ticket_items.MarginsType.Value.NO_MARGINS) {
+ return false;
+ } else if (this.marginsType_.getValue() ==
+ print_preview.ticket_items.MarginsType.Value.MINIMUM) {
+ return true;
+ }
+ var margins;
+ if (this.marginsType_.getValue() ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ if (!this.customMargins_.isValid()) {
+ return false;
+ }
+ margins = this.customMargins_.getValue();
+ } else {
+ margins = this.documentInfo_.margins;
+ }
+ var orientEnum = print_preview.ticket_items.CustomMargins.Orientation;
+ return margins == null ||
+ margins.get(orientEnum.TOP) > 0 ||
+ margins.get(orientEnum.BOTTOM) > 0;
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return true;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return false;
+ }
+ };
+
+ // Export
+ return {
+ HeaderFooter: HeaderFooter
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/landscape.js b/chrome/browser/resources/print_preview/data/ticket_items/landscape.js
new file mode 100644
index 0000000..eac17bb
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/landscape.js
@@ -0,0 +1,72 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Landscape ticket item whose value is a {@code boolean} that indicates
+ * whether the document should be printed in landscape orientation.
+ * @param {!print_preview.CapabilitiesHolder} capabilitiesHolder Capabilities
+ * holder used to determine the default landscape value and if landscape
+ * printing is available.
+ * @param {!print_preview.DocumentInfo} documentInfo Information about the
+ * document to print.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function Landscape(capabilitiesHolder, documentInfo) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Capabilities holder used to determine the default landscape value and if
+ * landscape printing is available.
+ * @type {!print_preview.CapabilitiesHolder}
+ * @private
+ */
+ this.capabilitiesHolder_ = capabilitiesHolder;
+
+ /**
+ * Information about the document to print.
+ * @type {!print_preview.DocumentInfo}
+ * @private
+ */
+ this.documentInfo_ = documentInfo;
+ };
+
+ Landscape.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ // TODO(rltoscano): Technically, the print destination can still change
+ // the orientation of the print out (at least for cloud printers) if the
+ // document is not modifiable. But the preview wouldn't update in this
+ // case so it would be a bad user experience.
+ return this.documentInfo_.isModifiable &&
+ !this.documentInfo_.hasCssMediaStyles &&
+ this.capabilitiesHolder_.get().hasOrientationCapability;
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return this.capabilitiesHolder_.get().defaultIsLandscapeEnabled;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return false;
+ }
+ };
+
+ // Export
+ return {
+ Landscape: Landscape
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/margins_type.js b/chrome/browser/resources/print_preview/data/ticket_items/margins_type.js
new file mode 100644
index 0000000..3fe95f4
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/margins_type.js
@@ -0,0 +1,68 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Margins type ticket item whose value is a
+ * {@link print_preview.ticket_items.MarginsType.Value} that indicates what
+ * predefined margins type to use.
+ * @param {!print_preview.DocumentInfo} documentInfo Information about the
+ * document to print.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function MarginsType(documentInfo) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Information about the document to print.
+ * @type {!print_preview.DocumentInfo}
+ * @private
+ */
+ this.documentInfo_ = documentInfo;
+ };
+
+ /**
+ * Enumeration of margin types. Matches enum MarginType in
+ * printing/print_job_constants.h.
+ * @enum {number}
+ */
+ MarginsType.Value = {
+ DEFAULT: 0,
+ NO_MARGINS: 1,
+ MINIMUM: 2,
+ CUSTOM: 3
+ };
+
+ MarginsType.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return true;
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return this.documentInfo_.isModifiable;
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return MarginsType.Value.DEFAULT;
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return MarginsType.Value.DEFAULT;
+ }
+ };
+
+ // Export
+ return {
+ MarginsType: MarginsType
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/page_range.js b/chrome/browser/resources/print_preview/data/ticket_items/page_range.js
new file mode 100644
index 0000000..2fc7152
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/page_range.js
@@ -0,0 +1,70 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * Page range ticket item whose value is a {@code string} that represents
+ * which pages in the document should be printed.
+ * @param {!print_preview.DocumentInfo} documentInfo Information about the
+ * document to print.
+ * @constructor
+ * @extends {print_preview.ticket_items.TicketItem}
+ */
+ function PageRange(documentInfo) {
+ print_preview.ticket_items.TicketItem.call(this);
+
+ /**
+ * Information about the document to print.
+ * @type {!print_preview.DocumentInfo}
+ * @private
+ */
+ this.documentInfo_ = documentInfo;
+ };
+
+ PageRange.prototype = {
+ __proto__: print_preview.ticket_items.TicketItem.prototype,
+
+ /** @override */
+ wouldValueBeValid: function(value) {
+ return value == '' ||
+ isPageRangeTextValid(value, this.documentInfo_.pageCount);
+ },
+
+ /**
+ * @return {!print_preview.PageNumberSet} Set of page numbers defined by the
+ * page range string.
+ */
+ getPageNumberSet: function() {
+ if (this.isValid()) {
+ return print_preview.PageNumberSet.parse(
+ this.getValue(), this.documentInfo_.pageCount);
+ } else {
+ return print_preview.PageNumberSet.parse(
+ this.getDefaultValueInternal(), this.documentInfo_.pageCount);
+ }
+ },
+
+ /** @override */
+ isCapabilityAvailable: function() {
+ return true;
+ },
+
+ /** @override */
+ getDefaultValueInternal: function() {
+ return '';
+ },
+
+ /** @override */
+ getCapabilityNotAvailableValueInternal: function() {
+ return '';
+ }
+ };
+
+ // Export
+ return {
+ PageRange: PageRange
+ };
+});
diff --git a/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js b/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js
new file mode 100644
index 0000000..1dffd20
--- /dev/null
+++ b/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js
@@ -0,0 +1,95 @@
+// 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.ticket_items', function() {
+ 'use strict';
+
+ /**
+ * An object that represents a user modifiable item in a print ticket. Each
+ * ticket item has a value which can be set by the user. Ticket items can also
+ * be unavailable for modifying if the print destination doesn't support it or
+ * if other ticket item constraints are not met.
+ * @constructor
+ */
+ function TicketItem() {
+ /**
+ * Backing store of the print ticket item.
+ * @type {Object}
+ * @private
+ */
+ this.value_ = null;
+ };
+
+ TicketItem.prototype = {
+ /**
+ * Determines whether a given value is valid for the ticket item.
+ * @param {Object} value The value to check for validity.
+ * @return {boolean} Whether the given value is valid for the ticket item.
+ */
+ wouldValueBeValid: function(value) {
+ throw Error('Abstract method not overridden');
+ },
+
+ /**
+ * @return {boolean} Whether the print destination capability is available.
+ */
+ isCapabilityAvailable: function() {
+ throw Error('Abstract method not overridden');
+ },
+
+ /** @return {object} The value of the ticket item. */
+ getValue: function() {
+ if (this.isCapabilityAvailable()) {
+ if (this.value_ == null) {
+ return this.getDefaultValueInternal();
+ } else {
+ return this.value_;
+ }
+ } else {
+ return this.getCapabilityNotAvailableValueInternal();
+ }
+ },
+
+ /** @return {boolean} Whether the ticket item was modified by the user. */
+ isUserEdited: function() {
+ return this.value_ != null;
+ },
+
+ /** @return {boolean} Whether the ticket item's value is valid. */
+ isValid: function() {
+ if (!this.isUserEdited()) {
+ return true;
+ }
+ return this.wouldValueBeValid(this.value_);
+ },
+
+ /** @param {object} Value to set as the value of the ticket item. */
+ updateValue: function(value) {
+ this.value_ = value;
+ },
+
+ /**
+ * @return {object} Default value of the ticket item if no value was set by
+ * the user.
+ * @protected
+ */
+ getDefaultValueInternal: function() {
+ throw Error('Abstract method not overridden');
+ },
+
+ /**
+ * @return {object} Default value of the ticket item if the capability is
+ * not available.
+ * @protected
+ */
+ getCapabilityNotAvailableValueInternal: function() {
+ throw Error('Abstract method not overridden');
+ }
+ };
+
+ // Export
+ return {
+ TicketItem: TicketItem
+ };
+});
diff --git a/chrome/browser/resources/print_preview/fit_to_page_settings.js b/chrome/browser/resources/print_preview/fit_to_page_settings.js
deleted file mode 100644
index 6747127..0000000
--- a/chrome/browser/resources/print_preview/fit_to_page_settings.js
+++ /dev/null
@@ -1,114 +0,0 @@
-// 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 |FitToPageSettings| object. This object encapsulates all
- * settings and logic related to the fit to page checkbox.
- * @constructor
- */
- function FitToPageSettings() {
- // @type {HTMLDivElement} This represents fit to page div element.
- this.fitToPageOption_ = $('fit-to-page-option');
-
- // @type {HTMLInputElement} This represents fit to page input element.
- this.fitToPageCheckbox_ = $('fit-to-page');
-
- // @type {boolean} True if fit to page option applies for the selected
- // user options. Fit to Page options applies only if we are previewing
- // a PDF and the current destination printer is actually a physcial
- // printer.
- this.fitToPageApplies_ = true;
-
- this.addEventListeners_();
- }
-
- cr.addSingletonGetter(FitToPageSettings);
-
- FitToPageSettings.prototype = {
- /**
- * Returns true if we need to fit the page contents to printable area.
- * @return {boolean} true if Fit to page is checked.
- */
- hasFitToPage: function() {
- return previewModifiable || this.fitToPageCheckbox_.checked;
- },
-
- /**
- * Updates |this.fitToPageApplies_| depending on the selected printer and
- * preview data source type.
- * @param {!string} printerName Selected printer name.
- * @private
- */
- resetState_: function(printerName) {
- if (!previewModifiable)
- isPrintReadyMetafileReady = false;
- var printToPDF = printerName == PRINT_TO_PDF;
- this.fitToPageApplies_ = !previewModifiable && !printToPDF;
- },
-
- /**
- * Print scaling is disabled for preview source plugin. Uncheck the fit to
- * page option.
- */
- onPrintScalingDisabled: function() {
- this.fitToPageCheckbox_.checked = false;
- },
-
- /**
- * Adding listeners to fit to page control.
- * @private
- */
- addEventListeners_: function() {
- this.fitToPageCheckbox_.onclick =
- this.onFitToPageCheckboxClicked_.bind(this);
- document.addEventListener(customEvents.PDF_LOADED,
- this.onPDFLoaded_.bind(this));
- document.addEventListener(customEvents.PRINTER_SELECTION_CHANGED,
- this.onPrinterSelectionChanged_.bind(this));
- },
-
- /**
- * Listener executing when a |customEvents.PRINTER_SELECTION_CHANGED| event
- * occurs.
- * @param {cr.Event} event The event that triggered this listener.
- * @private
- */
- onPrinterSelectionChanged_: function(event) {
- this.resetState_(event.selectedPrinter);
- this.updateVisibility_();
- },
-
- /**
- * Listener executing when the user selects or de-selects the fit to page
- * option.
- * @private
- */
- onFitToPageCheckboxClicked_: function() {
- requestPrintPreview();
- },
-
- /**
- * Listener executing when a |customEvents.PDF_LOADED| event occurs.
- * @private
- */
- onPDFLoaded_: function() {
- this.updateVisibility_();
- },
-
- /**
- * Hides or shows |this.fitToPageOption_|.
- * @private
- */
- updateVisibility_: function() {
- this.fitToPageOption_.style.display =
- this.fitToPageApplies_ ? 'block' : 'none';
- }
- };
-
- return {
- FitToPageSettings: FitToPageSettings
- };
-});
diff --git a/chrome/browser/resources/print_preview/header_footer_settings.js b/chrome/browser/resources/print_preview/header_footer_settings.js
deleted file mode 100644
index df74c67..0000000
--- a/chrome/browser/resources/print_preview/header_footer_settings.js
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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 HeaderFooterSettings object. This object encapsulates all
- * settings and logic related to the headers and footers checkbox.
- * @constructor
- */
- function HeaderFooterSettings() {
- this.headerFooterOption_ = $('header-footer-option');
- this.headerFooterCheckbox_ = $('header-footer');
- this.addEventListeners_();
- }
-
- cr.addSingletonGetter(HeaderFooterSettings);
-
- HeaderFooterSettings.prototype = {
- /**
- * The checkbox corresponding to the headers and footers option.
- * @type {HTMLInputElement}
- */
- get headerFooterCheckbox() {
- return this.headerFooterCheckbox_;
- },
-
- /**
- * Checks whether the Headers and Footers checkbox is checked or not.
- * @return {boolean} true if Headers and Footers are checked.
- */
- hasHeaderFooter: function() {
- return previewModifiable && this.headerFooterCheckbox_.checked;
- },
-
- /**
- * Sets the state of the headers footers checkbox.
- * @param {boolean} checked True if the headers footers checkbox shoule be
- * checked, false if not.
- */
- setChecked: function(checked) {
- this.headerFooterCheckbox_.checked = checked;
- },
-
- /**
- * Checks the printable area and updates the visibility of header footer
- * option based on the selected margins.
- * @param {{contentWidth: number, contentHeight: number, marginLeft: number,
- * marginRight: number, marginTop: number, marginBottom: number,
- * printableAreaX: number, printableAreaY: number,
- * printableAreaWidth: number, printableAreaHeight: number}}
- * pageLayout Specifies default page layout details in points.
- * @param {number} marginsType Specifies the selected margins type value.
- */
- checkAndHideHeaderFooterOption: function(pageLayout, marginsType) {
- var headerFooterApplies = true;
- if (marginsType ==
- print_preview.MarginSettings.MARGINS_VALUE_NO_MARGINS ||
- !previewModifiable) {
- headerFooterApplies = false;
- } else if (marginsType !=
- print_preview.MarginSettings.MARGINS_VALUE_MINIMUM) {
- if (cr.isLinux || cr.isChromeOS) {
- headerFooterApplies = pageLayout.marginTop > 0 ||
- pageLayout.marginBottom > 0;
- } else {
- var pageHeight = pageLayout.marginTop + pageLayout.marginBottom +
- pageLayout.contentHeight;
- headerFooterApplies =
- (pageLayout.marginTop > pageLayout.printableAreaY) ||
- (pageLayout.marginBottom >
- (pageHeight - pageLayout.printableAreaY -
- pageLayout.printableAreaHeight));
- }
- }
- this.setVisible_(headerFooterApplies);
- var headerFooterEvent = new cr.Event(
- customEvents.HEADER_FOOTER_VISIBILITY_CHANGED);
- headerFooterEvent.headerFooterApplies = headerFooterApplies;
- document.dispatchEvent(headerFooterEvent);
- },
-
- /**
- * Adding listeners to header footer related controls.
- * @private
- */
- addEventListeners_: function() {
- this.headerFooterCheckbox_.onclick =
- this.onHeaderFooterChanged_.bind(this);
- document.addEventListener(customEvents.PDF_LOADED,
- this.onPDFLoaded_.bind(this));
- },
-
- /**
- * Listener executing when the user selects or de-selects the headers
- * and footers option.
- * @private
- */
- onHeaderFooterChanged_: function() {
- requestPrintPreview();
- },
-
- /**
- * Listener executing when a |customEvents.PDF_LOADED| event occurs.
- * @private
- */
- onPDFLoaded_: function() {
- if (!previewModifiable)
- this.setVisible_(false);
- },
-
- /**
- * Hides or shows |this.headerFooterOption_|.
- * @param {boolean} visible True if |this.headerFooterOption_| should be
- * shown.
- * @private
- */
- setVisible_: function(visible) {
- this.headerFooterOption_.style.display = visible ? 'block' : 'none';
- },
- };
-
- return {
- HeaderFooterSettings: HeaderFooterSettings
- };
-});
diff --git a/chrome/browser/resources/print_preview/layout_settings.html b/chrome/browser/resources/print_preview/layout_settings.html
deleted file mode 100644
index 8bdf80f..0000000
--- a/chrome/browser/resources/print_preview/layout_settings.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<div id="layout-option" class="two-column visible">
- <h1 i18n-content="layoutLabel"></h1>
- <div class="right-column">
- <div class="radio"><label>
- <input id="portrait" type="radio" name="layout" checked>
- <span i18n-content="optionPortrait"></span>
- </label></div>
- <div class="radio"><label>
- <input id="landscape" type="radio" name="layout">
- <span i18n-content="optionLandscape"></span>
- </label></div>
- </div>
-</div>
diff --git a/chrome/browser/resources/print_preview/layout_settings.js b/chrome/browser/resources/print_preview/layout_settings.js
deleted file mode 100644
index e6cc097..0000000
--- a/chrome/browser/resources/print_preview/layout_settings.js
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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 LayoutSettings object. This object encapsulates all settings and
- * logic related to layout mode (portrait/landscape).
- * @constructor
- */
- function LayoutSettings() {
- this.layoutOption_ = $('layout-option');
- this.portraitRadioButton_ = $('portrait');
- this.landscapeRadioButton_ = $('landscape');
- this.wasLandscape_ = false;
- this.updateState();
- this.addEventListeners_();
- }
-
- cr.addSingletonGetter(LayoutSettings);
-
- LayoutSettings.prototype = {
- /**
- * The radio button corresponding to the portrait option.
- * @type {HTMLInputElement}
- */
- get portraitRadioButton() {
- return this.portraitRadioButton_;
- },
-
- /**
- * The radio button corresponding to the landscape option.
- * @type {HTMLInputElement}
- */
- get landscapeRadioButton() {
- return this.landscapeRadioButton_;
- },
-
- /**
- * @return {boolean} true if |this.landscapeRadioButton_| is checked, false
- * if not.
- */
- isLandscape: function() {
- return this.landscapeRadioButton_.checked;
- },
-
- /**
- * @return {boolean} true if the chosen layout mode has changed since last
- * time the state was updated.
- */
- hasChanged_: function() {
- return this.isLandscape() != this.wasLandscape_;
- },
-
- /**
- * Saves the currently selected layout mode. Used in |this.hasChanged_|.
- */
- updateState: function() {
- this.wasLandscape_ = this.isLandscape();
- },
-
- /**
- * Adding listeners to all layout related controls. The listeners take care
- * of altering their behavior depending on |hasPendingPreviewRequest|.
- * @private
- */
- addEventListeners_: function() {
- this.landscapeRadioButton_.onclick = this.onLayoutButtonClick_.bind(this);
- this.portraitRadioButton_.onclick = this.onLayoutButtonClick_.bind(this);
- document.addEventListener(customEvents.PDF_LOADED,
- this.onPDFLoaded_.bind(this));
- document.addEventListener(customEvents.PRINTER_CAPABILITIES_UPDATED,
- this.onPrinterCapabilitiesUpdated_.bind(this));
- },
-
- /**
- * Executes when a |customEvents.PRINTER_CAPABILITIES_UPDATED| event occurs.
- * @private
- */
- onPrinterCapabilitiesUpdated_: function(e) {
- if (e.printerCapabilities.disableLandscapeOption)
- this.fadeInOut_(e.printerCapabilities.disableLandscapeOption);
- },
-
- /**
- * Listener executing when |this.landscapeRadioButton_| or
- * |this.portraitRadioButton_| is clicked.
- * @private
- */
- onLayoutButtonClick_: function() {
- // If the chosen layout is same as before, nothing needs to be done.
- if (this.hasChanged_())
- setDefaultValuesAndRegeneratePreview(true);
- },
-
- /**
- * Listener executing when a |customEvents.PDF_LOADED| event occurs.
- * @private
- */
- onPDFLoaded_: function() {
- this.fadeInOut_(!previewModifiable || hasPageSizeStyle);
- },
-
- /**
- * @param {boolean} fadeOut True if |this.layoutOption_| should be faded
- * out, false if it should be faded in.
- * @private
- */
- fadeInOut_: function(fadeOut) {
- fadeOut ? fadeOutOption(this.layoutOption_) :
- fadeInOption(this.layoutOption_);
- }
- };
-
- return {
- LayoutSettings: LayoutSettings
- };
-});
diff --git a/chrome/browser/resources/print_preview/margin_settings.js b/chrome/browser/resources/print_preview/margin_settings.js
deleted file mode 100644
index 0ffca9f..0000000
--- a/chrome/browser/resources/print_preview/margin_settings.js
+++ /dev/null
@@ -1,705 +0,0 @@
-// 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 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) {
- if (!rhs)
- return false;
- 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];
- },
-
- clone: function() {
- return new Margins(this[MarginSettings.LEFT_GROUP],
- this[MarginSettings.TOP_GROUP],
- this[MarginSettings.RIGHT_GROUP],
- this[MarginSettings.BOTTOM_GROUP]);
- },
-
- /**
- * Helper method returning an array of the string indices used for accessing
- * all margins.
- * @return {array} An array of string indices.
- * @private
- */
- indicesAsArray_: function() {
- return [MarginSettings.LEFT_GROUP, MarginSettings.TOP_GROUP,
- MarginSettings.RIGHT_GROUP, MarginSettings.BOTTOM_GROUP];
- },
-
- /**
- * Rounds |this| based on the precision used when displaying the margins in
- * the user's prefered units. This is done by converting from points to
- * those units (mm/inches) and back to points.
- */
- roundToLocaleUnits: function() {
- var indicesAsArray = this.indicesAsArray_();
- for (var i = 0; i < indicesAsArray.length; i++) {
- this[indicesAsArray[i]] =
- print_preview.convertPointsToLocaleUnitsAndBack(
- this[indicesAsArray[i]]);
- }
- }
- };
-
- /**
- * @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);
- this.margins_.roundToLocaleUnits();
- }
-
- 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
- */
- function MarginSettings() {
- this.marginsOption_ = $('margins-option');
- this.marginList_ = $('margin-list');
- this.marginsUI_ = null;
-
- // Holds the custom margin values in points (if set).
- this.customMargins_ = null;
- // Holds the previous custom margin values in points.
- this.previousCustomMargins_ = null;
- // Holds the width of the page in points.
- this.pageWidth_ = -1;
- // Holds the height of the page in points.
- this.pageHeight_ = -1;
- // @type {boolean} True if the margins UI should be diplayed when the next
- // |customEvents.PDF_LOADED| event occurs.
- this.forceMarginsUIOnPDFLoad_ = false;
- // Holds the currently updated default page layout values.
- this.currentDefaultPageLayout = null;
-
- // True if the margins UI should be shown regardless of mouse position.
- this.forceDisplayingMarginLines_ = true;
-
- // @type {EventTracker} Used to keep track of certain event listeners.
- this.eventTracker_ = new EventTracker();
-
- this.addEventListeners_();
- }
-
- // Number of points per inch.
- MarginSettings.POINTS_PER_INCH = 72;
- // Minimum allowed distance in points between top-bottom, left-right margins.
- MarginSettings.MINIMUM_MARGINS_DISTANCE = 36;
- // Margin list values. Matches enum MarginType in
- // printing/print_job_constants.h.
- MarginSettings.MARGINS_VALUE_DEFAULT = 0;
- MarginSettings.MARGINS_VALUE_NO_MARGINS = 1;
- MarginSettings.MARGINS_VALUE_MINIMUM = 2;
- MarginSettings.MARGINS_VALUE_CUSTOM = 3;
- // Default Margins option index.
- MarginSettings.OPTION_INDEX_DEFAULT = 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';
-
- /**
- * Extracts the number formatting and measurement system for the current
- * locale.
- * @param {string} numberFormat Is the formatted version of a sample number
- * sent from the backend.
- * @param {number} measurementSystem 0 for SI (aka metric system), 1 for the
- * system used in the US. Note: Mathces UMeasurementSystem enum in
- * third_party/icu/public/i18n/unicode/ulocdata.h.
- */
- MarginSettings.setNumberFormatAndMeasurementSystem = function(
- numberFormat, measurementSystem) {
- var symbols = parseNumberFormat(numberFormat);
- MarginSettings.thousandsPoint = symbols[0];
- MarginSettings.decimalPoint = symbols[1];
- MarginSettings.useMetricSystem = measurementSystem == 0;
- };
-
- cr.addSingletonGetter(MarginSettings);
-
- MarginSettings.prototype = {
- /**
- * Returns a dictionary containing the four custom margin values.
- * @return {{marginLeft: number, marginTop: number, marginRight: number,
- * marginBottom: number}} The dictionary.
- */
- get customMargins() {
- var margins = {};
- margins.marginLeft = this.customMargins_.left;
- margins.marginTop = this.customMargins_.top;
- margins.marginRight = this.customMargins_.right;
- margins.marginBottom = this.customMargins_.bottom;
- return margins;
- },
-
- /**
- * Sets |this.customMargins_| according to |margins|.
- * @param {{marginLeft: number, marginTop: number, marginRight: number,
- * marginBottom: number}} margins An object holding the four margin
- * values.
- */
- set customMargins(margins) {
- this.customMargins_.left = margins.marginLeft;
- this.customMargins_.top = margins.marginTop;
- this.customMargins_.right = margins.marginRight;
- this.customMargins_.bottom = margins.marginBottom;
- },
-
- /**
- * @return {number} The value of the selected margin option.
- */
- get selectedMarginsValue() {
- var val = this.marginList_.options[this.marginList_.selectedIndex].value;
- return parseInt(val, 10);
- },
-
- /**
- * Sets the current margin selection to |lastUsedMarginType|.
- * @param {number} lastUsedMarginType An integer value identifying a margin
- * type according to MarginType enum in printing/print_job_constants.h.
- * @param {Object} lastUsedCustomMargins The last used custom margins. If
- * custom margins have not been used before
- * |margin{Top|Bottom|Left|Right}| attributes are missing.
- */
- setLastUsedMargins: function(lastUsedMarginsSettings) {
- var lastUsedMarginsType = lastUsedMarginsSettings['marginsType'];
- this.forceMarginsUIOnPDFLoad_ =
- lastUsedMarginsType == MarginSettings.MARGINS_VALUE_CUSTOM;
- this.marginList_.selectedIndex =
- this.getMarginOptionIndexByValue_(lastUsedMarginsType);
- if (lastUsedMarginsSettings.hasOwnProperty('marginTop') &&
- lastUsedMarginsSettings.hasOwnProperty('marginBottom') &&
- lastUsedMarginsSettings.hasOwnProperty('marginRight') &&
- lastUsedMarginsSettings.hasOwnProperty('marginLeft')) {
- this.customMargins_ = new Margins(-1, -1, -1 , -1);
- this.customMargins = lastUsedMarginsSettings;
- }
- },
-
- /**
- * @return {number} The total width of the plugin in points.
- */
- get totalWidthInPoints() {
- var pageInformation = previewArea.pageLocationNormalized;
- return this.pageWidth_ / pageInformation.width;
- },
-
- /**
- * @return {number} The total height of the plugin in points.
- */
- get totalHeightInPoints() {
- var pageInformation = previewArea.pageLocationNormalized;
- return this.pageHeight_ / pageInformation.height;
- },
-
- /**
- * Maps margin type values to indices within |this.marginList_|.
- * @param {number} marginTypeValue An integer value identifying a margin
- * type according to MarginType enum in printing/print_job_constants.h.
- * @return {number} The index within |this.marginList_| that corrsponds to
- * |marginTypeValue|.
- * @private
- */
- getMarginOptionIndexByValue_: function(marginTypeValue) {
- var options = this.marginList_.options;
- for (var i = 0; i < options.length; i++) {
- if (options[i].getAttribute('value') == marginTypeValue)
- return i;
- }
- return MarginSettings.OPTION_INDEX_DEFAULT;
- },
-
- /**
- * @return {boolean} True if default margins are selected.
- */
- isDefaultMarginsSelected: function() {
- return this.selectedMarginsValue == MarginSettings.MARGINS_VALUE_DEFAULT;
- },
-
- /**
- * @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;
- },
-
- /**
- * @return {boolean} True if minimum margins are selected.
- */
- isMinimumMarginsSelected: function() {
- return this.selectedMarginsValue == MarginSettings.MARGINS_VALUE_MINIMUM;
- },
-
- /**
- * 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_.isEqual(this.previousCustomMargins_))
- return;
-
- this.previousCustomMargins_ = this.customMargins_.clone();
- 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) {
- $('mainview').onmouseover = this.onMainviewMouseOver_.bind(this);
- $('navbar-container').onmouseover = null;
- if (!this.forceDisplayingMarginLines_)
- this.marginsUI.hide(false);
- },
-
- /**
- * 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() {
- $('mainview').onmouseover = null;
- $('navbar-container').onmouseover = this.onSidebarMouseOver_.bind(this);
- this.forceDisplayingMarginLines_ = false;
- this.marginsUI.show();
- },
-
- /**
- * Adds listeners to all margin related controls.
- * @private
- */
- addEventListeners_: function() {
- this.marginList_.onchange = this.onMarginsChanged_.bind(this);
- document.addEventListener(customEvents.PDF_LOADED,
- this.onPDFLoaded_.bind(this));
- document.addEventListener(customEvents.PDF_GENERATION_ERROR,
- this.onPDFGenerationError_.bind(this));
- },
-
- /**
- * Executes when a |customEvents.PDF_GENERATION_ERROR| event occurs.
- * @private
- */
- onPDFGenerationError_: function() {
- if (this.isCustomMarginsSelected()) {
- this.removeCustomMarginEventListeners_();
- this.marginsUI.hide(true);
- }
- },
-
- /**
- * Executes whenever a |customEvents.MARGIN_LINE_DRAG| occurs.
- * @param {cr.Event} e The event that triggered this listener.
- */
- onMarginsLineDrag_: function(e) {
- var dragDeltaInPoints = this.convertDragDeltaToPoints_(e.dragDelta);
- this.marginsUI.lastClickedMarginsUIPair.updateWhileDragging(
- dragDeltaInPoints, e.destinationPoint);
- },
-
- /**
- * @param {number} dragDelta The difference in pixels between the original
- * and current postion of the last clicked margin line.
- * @return {number} The difference in points.
- * @private
- */
- convertDragDeltaToPoints_: function(dragDelta) {
- if (this.marginsUI.lastClickedMarginsUIPair.isTop_() ||
- this.marginsUI.lastClickedMarginsUIPair.isBottom_()) {
- return dragDelta * this.totalHeightInPoints;
- } else {
- return dragDelta * this.totalWidthInPoints;
- }
- },
-
- /**
- * @return {boolean} True if the margin settings are valid.
- */
- areMarginSettingsValid: function() {
- if (!this.isCustomMarginsSelected() || !this.marginsUI_)
- 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 points in order top, left,
- * right, bottom.
- * @private
- */
- getMarginValueLimits_: function() {
- var marginValueLimits = [];
- marginValueLimits[0] = this.pageHeight_ - this.customMargins_.bottom -
- MarginSettings.MINIMUM_MARGINS_DISTANCE;
- marginValueLimits[1] = this.pageWidth_ - this.customMargins_.right -
- MarginSettings.MINIMUM_MARGINS_DISTANCE;
- marginValueLimits[2] = this.pageWidth_ - this.customMargins_.left -
- MarginSettings.MINIMUM_MARGINS_DISTANCE;
- marginValueLimits[3] = this.pageHeight_ - this.customMargins_.top -
- MarginSettings.MINIMUM_MARGINS_DISTANCE;
-
- for (var i = 0; i < marginValueLimits.length; i++) {
- marginValueLimits[i] = Math.max(marginValueLimits[i], 0);
- marginValueLimits[i] = print_preview.convertPointsToLocaleUnitsAndBack(
- marginValueLimits[i]);
- }
- return marginValueLimits;
- },
-
- /**
- * @return {array} The margin value limits positions normalized to the total
- * width and height of the plugin and with respect to the top left
- * corner of the plugin.
- */
- getMarginValueLimitsInPercent_: function() {
- var pageInformation = previewArea.pageLocationNormalized;
- var totalWidthInPoints = this.pageWidth_ / pageInformation.width;
- var totalHeightInPoints = this.pageHeight_ / pageInformation.height;
- var marginValueLimits = this.getMarginValueLimits_();
- var marginValueLimitsInPercent = [];
- marginValueLimitsInPercent[0] = pageInformation.y + marginValueLimits[0] /
- totalHeightInPoints;
- marginValueLimitsInPercent[1] = pageInformation.x + marginValueLimits[1] /
- totalWidthInPoints;
- marginValueLimitsInPercent[2] = pageInformation.x +
- pageInformation.width - marginValueLimits[2] / totalWidthInPoints;
- marginValueLimitsInPercent[3] = pageInformation.y +
- pageInformation.height - marginValueLimits[3] / totalHeightInPoints;
- return marginValueLimitsInPercent;
- },
-
- /**
- * 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 =
- print_preview.convertLocaleUnitsToPoints(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').appendChild(this.marginsUI_);
- 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);
- $('navbar-container').onmouseover = this.onSidebarMouseOver_.bind(this);
- this.eventTracker_.add(this.marginsUI,
- customEvents.MARGIN_LINE_DRAG,
- this.onMarginsLineDrag_.bind(this),
- false);
- this.eventTracker_.add(document, customEvents.MARGIN_TEXTBOX_FOCUSED,
- this.onMarginTextboxFocused_.bind(this), false);
- },
-
- /**
- * Removes the event listeners associated with the custom margins option.
- * @private
- */
- removeCustomMarginEventListeners_: function() {
- if (!this.marginsUI_)
- return;
- $('mainview').onmouseover = null;
- $('navbar-container').onmouseover = null;
- this.eventTracker_.remove(this.marginsUI, customEvents.MARGIN_LINE_DRAG);
- this.eventTracker_.remove(document, customEvents.MARGIN_TEXTBOX_FOCUSED);
- this.marginsUI.hide(true);
- },
-
- /**
- * 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.
- previewArea.update();
- var keepDisplayedValue = !this.areMarginSettingsValid();
- this.marginsUI.update(this.getMarginsRectangleInPercent_(),
- this.customMargins_,
- this.getMarginValueLimits_(),
- keepDisplayedValue,
- this.getMarginValueLimitsInPercent_());
- this.marginsUI.draw();
- },
-
- /**
- * Called when there is change in the preview position or size.
- */
- onPreviewPositionChanged: function() {
- if (!previewArea.pdfPlugin)
- return;
- if (this.isCustomMarginsSelected() && previewArea.pdfLoaded &&
- pageSettings.totalPageCount != undefined) {
- this.updatePageData_();
- this.drawCustomMarginsUI_();
- }
- },
-
- /**
- * Executes when a margin textbox is focused. Used for improved
- * accessibility.
- * @private
- */
- onMarginTextboxFocused_: function() {
- this.forceDisplayingMarginLines_ = true;
- this.marginsUI.show();
- },
-
- /**
- * Executes when user selects a different margin option, ie,
- * |this.marginList_.selectedIndex| is changed.
- * @private
- */
- onMarginsChanged_: function() {
- if (this.isDefaultMarginsSelected() || this.isMinimumMarginsSelected() ||
- this.isNoMarginsSelected())
- this.onDefaultMinimumNoMarginsSelected_();
- else if (this.isCustomMarginsSelected())
- this.onCustomMarginsSelected_();
- },
-
- /**
- * Executes when the default or minimum or no margins option is selected.
- * @private
- */
- onDefaultMinimumNoMarginsSelected_: function() {
- this.removeCustomMarginEventListeners_();
- this.forceDisplayingMarginLines_ = true;
- this.previousCustomMargins_ = null;
- setDefaultValuesAndRegeneratePreview(false);
- },
-
- /**
- * Executes when the custom margins option is selected.
- * @private
- */
- onCustomMarginsSelected_: function() {
- if (!previewArea.pdfPlugin) {
- this.forceMarginsUIOnPDFLoad_ = true;
- return;
- }
- var customMarginsNotSpecified = !this.customMargins_;
- this.updatePageData_();
-
- if (customMarginsNotSpecified) {
- this.previousCustomMargins_ = this.customMargins_.clone();
- this.drawCustomMarginsUI_();
- this.addCustomMarginEventListeners_();
- this.marginsUI.show();
- } else {
- this.forceMarginsUIOnPDFLoad_ = true;
- this.requestPreviewIfNeeded_();
- }
- },
-
- /**
- * 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.pageLocationNormalized;
- 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() {
- return this.convertMarginsInPointsToPercent(this.customMargins_);
- },
-
- /**
- * Converts |marginsToConvert| to points and normalizes it to the height and
- * width of the plugin.
- * @return {print_preview.Margins} The margins in percent.
- * @private
- */
- convertMarginsInPointsToPercent: function(marginsToConvert) {
- var pageInformation = previewArea.pageLocationNormalized;
- var totalWidthInPoints = this.pageWidth_ / pageInformation.width;
- var totalHeightInPoints = this.pageHeight_ / pageInformation.height;
- var marginsInPercent = new Margins(
- marginsToConvert.left / totalWidthInPoints,
- marginsToConvert.top / totalHeightInPoints,
- marginsToConvert.right / totalWidthInPoints,
- marginsToConvert.bottom / totalHeightInPoints);
- return marginsInPercent;
- },
-
- /**
- * If custom margins is the currently selected option then change to the
- * default margins option.
- * @private
- */
- resetMarginsIfNeeded: function() {
- if (this.isCustomMarginsSelected()) {
- this.marginList_.options[
- MarginSettings.OPTION_INDEX_DEFAULT].selected = true;
- this.removeCustomMarginEventListeners_();
- this.forceDisplayingMarginLines_ = true;
- this.customMargins_ = null;
- this.previousCustomMargins_ = null;
- }
- },
-
- /**
- * Executes when a |customEvents.PDF_LOADED| event occurs.
- * @private
- */
- onPDFLoaded_: function() {
- if (!previewModifiable) {
- fadeOutOption(this.marginsOption_);
- return;
- }
-
- if (this.forceMarginsUIOnPDFLoad_) {
- this.updatePageData_();
- this.drawCustomMarginsUI_();
- this.addCustomMarginEventListeners_();
- this.marginsUI.show();
- this.forceMarginsUIOnPDFLoad_ = false;
- }
- },
-
- /**
- * Updates |this.customMargins_|, |this.pageWidth_|, |this.pageHeight_|.
- * @private
- */
- updatePageData_: function() {
- if (!this.customMargins_)
- this.customMargins_ = this.currentDefaultPageLayout.margins_.clone();
-
- this.pageWidth_ = this.currentDefaultPageLayout.pageWidth;
- this.pageHeight_ = this.currentDefaultPageLayout.pageHeight;
- }
- };
-
- 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
deleted file mode 100644
index f0496f5..0000000
--- a/chrome/browser/resources/print_preview/margin_textbox.js
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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';
-
- 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';
- box.setAttribute('aria-label', localStrings.getString(groupName));
-
- // @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 {number} The upper allowed limit for the corresponding margin.
- box.valueLimit = null;
-
- box.addEventListeners_();
- return box;
- }
-
- MarginTextbox.CSS_CLASS_MARGIN_TEXTBOX = 'margin-box';
- // Keycode for the "Escape" key.
- MarginTextbox.ESCAPE_KEYCODE = 27;
-
- MarginTextbox.prototype = {
- __proto__: HTMLInputElement.prototype,
-
- /**
- * @type {number} The margin value currently in the textbox.
- */
- get margin() {
- return print_preview.extractMarginValue(this.value);
- },
-
- /**
- * Sets the contents of the textbox.
- * @param {number} newValueInPoints The value to be displayed in points.
- * @private
- */
- setValue_: function(newValueInPoints) {
- this.value =
- print_preview.convertPointsToLocaleUnitsText(newValueInPoints);
- },
-
- /**
- * Updates the state of |this|.
- * @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(value, valueLimit, keepDisplayedValue) {
- this.lastValidValueInPoints = value;
- if (!keepDisplayedValue)
- this.setValue_(this.lastValidValueInPoints);
-
- this.valueLimit = valueLimit;
- this.validate();
- },
-
- /**
- * Updates |this| while dragging is in progress.
- * @param {number} dragDeltaInPoints The difference in points between the
- * margin value before dragging started and now.
- */
- updateWhileDragging: function(dragDeltaInPoints) {
- var validity = this.validateDelta(dragDeltaInPoints);
-
- if (validity == print_preview.marginValidationStates.WITHIN_RANGE)
- this.setValue_(this.lastValidValueInPoints + dragDeltaInPoints);
- else if (validity == print_preview.marginValidationStates.TOO_SMALL)
- this.setValue_(0);
- else if (validity == print_preview.marginValidationStates.TOO_BIG)
- this.setValue_(this.valueLimit);
-
- this.validate();
- this.updateColor();
- },
-
- /**
- * @param {number} dragDeltaInPoints The difference in points between the
- * margin value before dragging started and now.
- * @return {number} An appropriate value from enum |marginValidationStates|.
- */
- validateDelta: function(dragDeltaInPoints) {
- var newValue = this.lastValidValueInPoints + dragDeltaInPoints;
- return print_preview.validateMarginValue(newValue, this.valueLimit);
- },
-
- /**
- * Updates |this.isValid|.
- */
- validate: function() {
- this.isValid =
- print_preview.validateMarginText(this.value, this.valueLimit) ==
- print_preview.marginValidationStates.WITHIN_RANGE;
- },
-
- /**
- * 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() {
- this.updateColor();
- },
-
- /**
- * 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);
- this.onfocus = function() {
- cr.dispatchSimpleEvent(document, customEvents.MARGIN_TEXTBOX_FOCUSED);
- };
- },
-
- /**
- * Executes whenever a blur event occurs.
- * @private
- */
- onBlur_: function() {
- clearTimeout(this.timerId_);
- this.validate();
- if (!this.isValid) {
- this.setValue_(this.lastValidValueInPoints);
- this.validate();
- }
-
- this.updateColor();
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- cr.dispatchSimpleEvent(this, customEvents.MARGINS_MAY_HAVE_CHANGED);
- },
-
- /**
- * 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.keyIdentifier == 'Enter')
- 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.setValue_(this.lastValidValueInPoints);
- this.validate();
- this.updateColor();
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- }
- },
-
- /**
- * 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), 1000);
- },
-
- /**
- * Executes whenever the user stops typing or when a drag session associated
- * with |this| ends.
- */
- onTextValueMayHaveChanged: function() {
- this.validate();
- this.updateColor();
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
-
- if (!this.isValid)
- return;
- cr.dispatchSimpleEvent(this, customEvents.MARGINS_MAY_HAVE_CHANGED);
- }
-
- };
-
- return {
- MarginTextbox: MarginTextbox
- };
-});
diff --git a/chrome/browser/resources/print_preview/margin_utils.js b/chrome/browser/resources/print_preview/margin_utils.js
deleted file mode 100644
index a93ef0e..0000000
--- a/chrome/browser/resources/print_preview/margin_utils.js
+++ /dev/null
@@ -1,187 +0,0 @@
-// 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';
-
- /**
- * 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) {
- // Removing whitespace anywhere in the string.
- text = text.replace(/\s*/g, '');
- if (text.length == 0)
- return -1;
- var validationRegex = getValidationRegExp();
- if (validationRegex.test(text)) {
- // Replacing decimal point with the dot symbol in order to use
- // parseFloat() properly.
- var replacementRegex = new RegExp('\\' +
- print_preview.MarginSettings.decimalPoint + '{1}');
- text = text.replace(replacementRegex, '.');
- return parseFloat(text);
- }
- return -1;
- }
-
- /**
- * @return {RegExp} A regular expression for validating the input of the user.
- * It takes into account the user's locale.
- */
- function getValidationRegExp() {
- var regex = new RegExp('(^\\d+)(\\' +
- print_preview.MarginSettings.thousandsPoint + '\\d{3})*(\\' +
- print_preview.MarginSettings.decimalPoint + '\\d+)*' +
- (!print_preview.MarginSettings.useMetricSystem ? '"?' : '(mm)?') + '$');
- return regex;
- }
-
- var marginValidationStates = {
- TOO_SMALL: 0,
- WITHIN_RANGE: 1,
- TOO_BIG: 2,
- NOT_A_NUMBER: 3
- };
-
- /**
- * Checks whether |value| is within range [0, limit].
- * @return {number} An appropriate value from enum |marginValidationStates|.
- */
- function validateMarginValue(value, limit) {
- if (value <= limit && value >= 0)
- return marginValidationStates.WITHIN_RANGE;
- else if (value < 0)
- return marginValidationStates.TOO_SMALL;
- else
- return marginValidationStates.TOO_BIG;
- }
-
- /**
- * @param {string} text The text to check in user's locale units.
- * @param {number} limit The upper bound of the valid margin range (in
- * points).
- * @return {number} An appropriate value from enum |marginValidationStates|.
- */
- function validateMarginText(text, limit) {
- var value = extractMarginValue(text);
- if (value == -1)
- return marginValidationStates.NOT_A_NUMBER;
- value = print_preview.convertLocaleUnitsToPoints(value);
- return validateMarginValue(value, limit);
- }
-
- /**
- * @param {number} value The value to convert in points.
- * @return {number} The corresponding value after converting to user's locale
- * units.
- */
- function convertPointsToLocaleUnits(value) {
- return print_preview.MarginSettings.useMetricSystem ?
- convertPointsToMillimeters(value) : convertPointsToInches(value);
- }
-
- /**
- * @param {number} value The value to convert in user's locale units.
- * @return {number} The corresponding value after converting to points.
- */
- function convertLocaleUnitsToPoints(value) {
- return print_preview.MarginSettings.useMetricSystem ?
- convertMillimetersToPoints(value) : convertInchesToPoints(value);
- }
-
- /**
- * Converts |value| to user's locale units and then back to points. Note:
- * Because of the precision the return value might be different than |value|.
- * @param {number} value The value in points to convert.
- * @return {number} The value in points after converting to user's locale
- * units with a certain precision and back.
- */
- function convertPointsToLocaleUnitsAndBack(value) {
- var inLocaleUnits =
- convertPointsToLocaleUnits(value).toFixed(getDesiredPrecision());
- return convertLocaleUnitsToPoints(inLocaleUnits);
- }
-
- /**
- * @return {number} The number of decimal digits to keep based on the
- * measurement system used.
- */
- function getDesiredPrecision() {
- return print_preview.MarginSettings.useMetricSystem ? 0 : 2;
- }
-
- /**
- * @param {number} value The value to convert in points.
- * @return {string} The equivalent text in user locale units with precision
- * of two digits.
- */
- function convertPointsToLocaleUnitsText(value) {
- var inLocaleUnits =
- convertPointsToLocaleUnits(value).toFixed(getDesiredPrecision());
- var inLocaleUnitsText = inLocaleUnits.toString(10).replace(
- /\./g, print_preview.MarginSettings.decimalPoint);
- return !print_preview.MarginSettings.useMetricSystem ?
- inLocaleUnitsText + '"' : inLocaleUnitsText + 'mm';
- }
-
- /**
- * 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 = {
- /**
- * @type {number} The x coordinate of the right-most point.
- */
- get right() {
- return this.x + this.width;
- },
-
- /**
- * @type {number} The y coordinate of the lower-most point.
- */
- get bottom() {
- return this.y + this.height;
- },
-
- /**
- * Clones |this| and returns the cloned object.
- * @return {Rect} A copy of |this|.
- */
- clone: function() {
- return new Rect(this.x, this.y, this.width, this.height);
- }
- };
-
- return {
- convertPointsToLocaleUnitsAndBack:
- convertPointsToLocaleUnitsAndBack,
- convertPointsToLocaleUnitsText: convertPointsToLocaleUnitsText,
- convertLocaleUnitsToPoints: convertLocaleUnitsToPoints,
- extractMarginValue: extractMarginValue,
- marginValidationStates: marginValidationStates,
- Rect: Rect,
- validateMarginText: validateMarginText,
- validateMarginValue: validateMarginValue
- };
-});
diff --git a/chrome/browser/resources/print_preview/margins.css b/chrome/browser/resources/print_preview/margins.css
deleted file mode 100644
index f2fd789..0000000
--- a/chrome/browser/resources/print_preview/margins.css
+++ /dev/null
@@ -1,100 +0,0 @@
-/* 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. */
-
-#print-preview .margin-box {
- background-color: #2a2a2a;
- border: 1px solid #888;
- box-sizing: border-box;
- color: white;
- cursor: auto;
- font-family: arial;
- font-size: 0.8em;
- height: 25px;
- left: 50%;
- padding: 5px 10px;
- position: absolute;
- text-align: center;
- top: 50%;
- width: 60px;
-}
-
-.margins-ui-pair.top .margin-box,
-.margins-ui-pair.bottom .margin-box {
- /* -width / 2 + 1 for the margin border */
- margin-left: -30px;
-}
-
-.margins-ui-pair.left .margin-box,
-.margins-ui-pair.right .margin-box {
- /* -height / 2 */
- margin-top: -12px;
-}
-
-.margins-ui-pair.bottom .margin-box {
- /* -height + 1 */
- margin-top: -23px;
-}
-
-.margins-ui-pair.right .margin-box {
- /* -width - 2 */
- margin-left: -58px;
-}
-
-.margin-box.invalid {
- background-color: rgb(193, 27, 23);
-}
-
-.margins-ui-pair {
- background-color: transparent;
- border-color: transparent;
- position: absolute;
-}
-
-.margins-ui-pair.right,
-.margins-ui-pair.left {
- cursor: ew-resize;
-}
-
-.margins-ui-pair.top,
-.margins-ui-pair.bottom {
- cursor: ns-resize;
-}
-
-.margins-ui-pair.dragging {
- z-index: 1;
-}
-
-.margin-line {
- border-color: rgb(64, 128, 250);
- border-style: dashed;
- border-width: 1px;
- pointer-events: none;
- position: absolute;
-}
-
-.margins-ui-pair.top .margin-line,
-.margins-ui-pair.bottom .margin-line {
- height: 0;
- left: 0;
- top: 50%;
- width: 100%;
-}
-
-.margins-ui-pair.left .margin-line,
-.margins-ui-pair.right .margin-line {
- height: 100%;
- left: 50%;
- top: 0;
- width: 0;
-}
-
-#customized-margins {
- position: absolute;
- top: 0;
-}
-
-#customized-margins.invisible {
- opacity: 0;
- pointer-events: none;
-}
diff --git a/chrome/browser/resources/print_preview/margins_ui.js b/chrome/browser/resources/print_preview/margins_ui.js
deleted file mode 100644
index c2d5309..0000000
--- a/chrome/browser/resources/print_preview/margins_ui.js
+++ /dev/null
@@ -1,213 +0,0 @@
-// 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';
-
- function MarginsUI() {
- var marginsUI = document.createElement('div');
- marginsUI.__proto__ = MarginsUI.prototype;
- marginsUI.id = 'customized-margins';
-
- // @type {print_preview.MarginsUIPair} The object corresponding to the top
- // margin.
- marginsUI.topPair_ = new print_preview.MarginsUIPair(
- print_preview.MarginSettings.TOP_GROUP);
- // @type {print_preview.MarginsUIPair} The object corresponding to the left
- // margin.
- marginsUI.leftPair_ = new print_preview.MarginsUIPair(
- print_preview.MarginSettings.LEFT_GROUP);
- // @type {print_preview.MarginsUIPair} The object corresponding to the right
- // margin.
- marginsUI.rightPair_ = new print_preview.MarginsUIPair(
- print_preview.MarginSettings.RIGHT_GROUP);
- // @type {print_preview.MarginsUIPair} The object corresponding to the
- // bottom margin.
- marginsUI.bottomPair_ = new print_preview.MarginsUIPair(
- print_preview.MarginSettings.BOTTOM_GROUP);
-
- var uiPairs = marginsUI.pairsAsList;
- for (var i = 0; i < uiPairs.length; i++)
- marginsUI.appendChild(uiPairs[i]);
-
- // @type {print_preview.MarginsUIPair} The object that is being dragged.
- // null if no drag session is in progress.
- marginsUI.lastClickedMarginsUIPair = null;
-
- // @type {EventTracker} Used to keep track of certain event listeners.
- marginsUI.eventTracker_ = new EventTracker();
-
- marginsUI.addEventListeners_();
- return marginsUI;
- }
-
- /**
- * @param {{x: number, y: number}} point The point with respect to the top
- * left corner of the webpage.
- * @return {{x: number, y: number}} The point with respect to the top left
- * corner of the plugin area.
- */
- MarginsUI.convert = function(point) {
- var mainview = $('mainview');
- return { x: point.x - mainview.offsetLeft,
- y: point.y - mainview.offsetTop };
- }
-
- MarginsUI.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * Adds an observer for |customEvents.MARGINS_MAY_HAVE_CHANGED| event.
- * @param {function} func A callback function to be called when
- * |customEvents.MARGINS_MAY_HAVE_CHANGED| event occurs.
- */
- addObserver: function(func) {
- var uiPairs = this.pairsAsList;
- for (var i = 0; i < uiPairs.length; i++) {
- uiPairs[i].box_.addEventListener(
- customEvents.MARGINS_MAY_HAVE_CHANGED, 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} marginsRectangle A rectangle describing the
- * four margins.
- * @param {Margins} marginValues The margin values in points.
- * @param {Array.<number>} valueLimits The maximum allowed margins for each
- * side in points.
- * @param {boolean} keepDisplayedValue True if the currently displayed
- * margin values should not be updated.
- * @param {Array.<number>} valueLimitsInPercent The maximum allowed margins
- * for each side in percentages.
- */
- update: function(marginsRectangle, marginValues, valueLimits,
- keepDisplayedValue, valueLimitsInPercent) {
- 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,
- valueLimitsInPercent[i]);
- }
- },
-
- /**
- * 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;
- this.classList.remove('invisible');
- },
-
- /**
- * Hides the margins UI and removes from the rendering flow if requested.
- * @param {boolean} removeFromFlow True if |this| should also be removed
- * from the rendering flow (in order to not interfere with the tab
- * order).
- */
- hide: function(removeFromFlow) {
- removeFromFlow ? this.hidden = true : this.classList.add('invisible');
- },
-
- /**
- * 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)';
- },
-
- /**
- * Adds event listeners for various events.
- * @private
- */
- addEventListeners_: function() {
- var uiPairs = this.pairsAsList;
- for (var i = 0; i < uiPairs.length; i++) {
- uiPairs[i].addEventListener(customEvents.MARGIN_LINE_MOUSE_DOWN,
- this.onMarginLineMouseDown.bind(this));
- }
- // After snapping to min/max the MarginUIPair might not receive the
- // mouseup event since it is not under the mouse pointer, so it is handled
- // here.
- window.document.addEventListener('mouseup',
- this.onMarginLineMouseUp.bind(this));
- },
-
- /**
- * Executes when a "MarginLineMouseDown" event occurs.
- * @param {cr.Event} e The event that triggered this listener.
- */
- onMarginLineMouseDown: function(e) {
- this.lastClickedMarginsUIPair = e.target;
- this.bringToFront(this.lastClickedMarginsUIPair);
- // Note: Capturing mouse events at a higher level in the DOM than |this|,
- // so that the plugin can still receive mouse events.
- this.eventTracker_.add(
- window.document, 'mousemove', this.onMouseMove_.bind(this), false);
- },
-
- /**
- * Executes when a "MarginLineMouseUp" event occurs.
- * @param {cr.Event} e The event that triggered this listener.
- */
- onMarginLineMouseUp: function(e) {
- if (this.lastClickedMarginsUIPair == null)
- return;
- this.lastClickedMarginsUIPair.onMouseUp();
- this.lastClickedMarginsUIPair = null;
- this.eventTracker_.remove(window.document, 'mousemove');
- },
-
- /**
- * Brings |uiPair| in front of the other pairs. Used to make sure that the
- * dragged pair is visible when overlapping with a not dragged pair.
- * @param {print_preview.MarginsUIPair} uiPair The pair to bring in front.
- */
- bringToFront: function(uiPair) {
- this.pairsAsList.forEach(function(pair) {
- pair.classList.remove('dragging');
- });
- uiPair.classList.add('dragging');
- },
-
- /**
- * Executes when a mousemove event occurs.
- * @param {MouseEvent} e The event that triggered this listener.
- */
- onMouseMove_: function(e) {
- var point = MarginsUI.convert({ x: e.x, y: e.y });
-
- var dragEvent = new cr.Event(customEvents.MARGIN_LINE_DRAG);
- dragEvent.dragDelta =
- this.lastClickedMarginsUIPair.getDragDisplacementFrom(point);
- dragEvent.destinationPoint = point;
- this.dispatchEvent(dragEvent);
- }
- };
-
- return {
- MarginsUI: MarginsUI
- };
-});
diff --git a/chrome/browser/resources/print_preview/margins_ui_pair.js b/chrome/browser/resources/print_preview/margins_ui_pair.js
deleted file mode 100644
index e35e9f2..0000000
--- a/chrome/browser/resources/print_preview/margins_ui_pair.js
+++ /dev/null
@@ -1,296 +0,0 @@
-// 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';
-
- /**
- * @constructor
- * This class represents a margin line and a textbox corresponding to that
- * margin.
- */
- function MarginsUIPair(groupName) {
- var marginsUIPair = document.createElement('div');
- marginsUIPair.__proto__ = MarginsUIPair.prototype;
- marginsUIPair.className = MarginsUIPair.CSS_CLASS;
- // @type {string} Specifies which margin this line refers to.
- marginsUIPair.marginGroup = groupName;
- marginsUIPair.classList.add(groupName);
-
- // @type {print_preview.Rect} A rectangle describing the dimensions of
- // the draggable area.
- marginsUIPair.rectangle = null;
- // @type {print_preview.Rect} A rectangle describing the four margins.
- marginsUIPair.marginsRectangle = null;
- // @type {HTMLDivElement} The line representing the margin.
- marginsUIPair.line_ = document.createElement('div');
- marginsUIPair.line_.className = 'margin-line';
- // @type {print_preview.MarginTextbox} The textbox corresponding to this
- // margin.
- marginsUIPair.box_ = new print_preview.MarginTextbox(groupName);
- // @type {{x: number, y: number}} The point where mousedown occured within
- // the draggable area with respect the top-left corner of |this|.
- marginsUIPair.mousePointerOffset = null;
- // @type {{x: number, y:number}} The position of the origin before any
- // dragging in progress occured.
- marginsUIPair.originBeforeDragging = null;
-
- marginsUIPair.appendChild(marginsUIPair.line_);
- marginsUIPair.appendChild(marginsUIPair.box_);
-
- marginsUIPair.addEventListeners_();
- return marginsUIPair;
- }
-
- MarginsUIPair.CSS_CLASS = 'margins-ui-pair';
- // Width of the clickable region around each margin line in screen pixels.
- MarginsUIPair.CLICKABLE_REGION = 20;
-
- MarginsUIPair.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * Updates the state.
- */
- update: function(marginsRectangle, value, valueLimit, keepDisplayedValue,
- valueLimitInPercent) {
- this.marginsRectangle = marginsRectangle;
- this.valueLimitInPercent = valueLimitInPercent;
- this.rectangle = this.getCoordinates_(this.marginsRectangle);
- this.box_.update(value, valueLimit, keepDisplayedValue);
- },
-
- /**
- * Draws |this| based on the state.
- */
- draw: function() {
- this.drawDraggableArea_();
- this.box_.draw();
- },
-
- /**
- * Draws the area that can be clicked in order to start dragging.
- * @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.pageLocationNormalized;
- var totalWidth = previewArea.pdfPlugin_.offsetWidth;
- var totalHeight = previewArea.pdfPlugin_.offsetHeight;
- var offsetY = (MarginsUIPair.CLICKABLE_REGION / 2) / totalHeight;
- var offsetX = (MarginsUIPair.CLICKABLE_REGION / 2) / totalWidth;
-
- if (this.isTop_()) {
- var lineCoordinates = new print_preview.Rect(
- pageLocation.x,
- marginsRectangle.y - offsetY,
- pageLocation.width,
- MarginsUIPair.CLICKABLE_REGION / totalHeight);
- } else if (this.isBottom_()) {
- var lineCoordinates = new print_preview.Rect(
- pageLocation.x,
- marginsRectangle.bottom - offsetY,
- pageLocation.width,
- MarginsUIPair.CLICKABLE_REGION / totalHeight);
- } else if (this.isRight_()) {
- var lineCoordinates = new print_preview.Rect(
- marginsRectangle.right - offsetX,
- pageLocation.y,
- MarginsUIPair.CLICKABLE_REGION / totalWidth,
- pageLocation.height);
- } else if (this.isLeft_()) {
- var lineCoordinates = new print_preview.Rect(
- marginsRectangle.x - offsetX,
- pageLocation.y,
- MarginsUIPair.CLICKABLE_REGION / totalWidth,
- pageLocation.height);
- }
- return lineCoordinates;
- },
-
- /**
- * @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;
- },
-
- /**
- * Adds event listeners for events related to dragging.
- */
- addEventListeners_: function() {
- this.onmousedown = this.onMouseDown_.bind(this);
- },
-
- /**
- * Executes whenever a mousedown event occurs on |this| or its child nodes.
- * @param {MouseEvent} e The event that occured.
- */
- onMouseDown_: function(e) {
- if (e.button != 0)
- return;
- if (e.target != this)
- return;
- var point = print_preview.MarginsUI.convert({x: e.x, y: e.y});
- this.originBeforeDragging = { x: this.offsetLeft, y: this.offsetTop };
- this.mousePointerOffset =
- { x: point.x - this.offsetLeft, y: point.y - this.offsetTop };
- cr.dispatchSimpleEvent(this, customEvents.MARGIN_LINE_MOUSE_DOWN);
- },
-
- /**
- * Executes whenever a mouseup event occurs while |this| is dragged.
- */
- onMouseUp: function() {
- this.box_.onTextValueMayHaveChanged();
- },
-
- /**
- * Moves |this| including all its children to |point|.
- * @param {{x: number, y: number}} point The point where |this| should be
- * moved.
- */
- moveTo: function(point) {
- if (this.isTop_() || this.isBottom_())
- this.style.top = point.y - this.mousePointerOffset.y + 'px';
- else
- this.style.left = point.x - this.mousePointerOffset.x + 'px';
- },
-
- /**
- * @param {{x: number, y: number}} rhs The point to compare with.
- * @return {number} The horizontal or vertical displacement in pixels
- * between |this.originBeforeDragging| and |rhs|. Note: Bottom margin
- * grows upwards, right margin grows when going to the left.
- */
- getDragDisplacementFrom: function(rhs) {
- var dragDisplacement = 0;
- if (this.isTop_() || this.isBottom_()) {
- dragDisplacement = (rhs.y - this.originBeforeDragging.y -
- this.mousePointerOffset.y) / previewArea.height;
- } else {
- dragDisplacement = (rhs.x - this.originBeforeDragging.x -
- this.mousePointerOffset.x) / previewArea.width;
- }
-
- if (this.isBottom_() || this.isRight_())
- dragDisplacement *= -1;
- return dragDisplacement;
- },
-
- /**
- * Updates |this| while dragging is in progress. Takes care of rejecting
- * invalid margin values.
- * @param {number} dragDeltaInPoints The difference in points between the
- * currently applied margin and the margin indicated by
- * |destinationPoint|.
- * @param {{x: number, y: number}} destinationPoint The point where the
- * margin line should be drawn if |dragDeltaInPoints| is applied.
- */
- updateWhileDragging: function(dragDeltaInPoints, destinationPoint) {
- this.box_.updateWhileDragging(dragDeltaInPoints);
- var validity = this.box_.validateDelta(dragDeltaInPoints);
- if (validity == print_preview.marginValidationStates.WITHIN_RANGE)
- this.moveTo(destinationPoint);
- else if (validity == print_preview.marginValidationStates.TOO_SMALL)
- this.snapToMinValue_();
- else if (validity == print_preview.marginValidationStates.TOO_BIG)
- this.snapToMaxValue_();
- },
-
- /**
- * Snaps |this| to the minimum allowed margin value (0). Happens whenever
- * the user drags the margin line to a smaller value than the minimum
- * allowed.
- * @private
- */
- snapToMinValue_: function() {
- var pageInformation = previewArea.pageLocationNormalized;
- var newMarginsRectangle = this.marginsRectangle.clone();
- if (this.isTop_()) {
- newMarginsRectangle.y = pageInformation.y;
- } else if (this.isLeft_()) {
- newMarginsRectangle.x = pageInformation.x;
- } else if (this.isRight_()) {
- newMarginsRectangle.x = pageInformation.x;
- newMarginsRectangle.width = pageInformation.width;
- } else if (this.isBottom_()) {
- newMarginsRectangle.y = pageInformation.y;
- newMarginsRectangle.height = pageInformation.height;
- }
-
- this.rectangle = this.getCoordinates_(newMarginsRectangle);
- this.drawDraggableArea_();
- },
-
- /**
- * Snaps |this| to the maximum allowed margin value. Happens whenever
- * the user drags the margin line to a larger value than the maximum
- * allowed.
- * @private
- */
- snapToMaxValue_: function() {
- var newMarginsRectangle = this.marginsRectangle.clone();
-
- if (this.isTop_()) {
- newMarginsRectangle.y = this.valueLimitInPercent;
- } else if (this.isLeft_()) {
- newMarginsRectangle.x = this.valueLimitInPercent;
- } else if (this.isRight_()) {
- newMarginsRectangle.x = 0;
- newMarginsRectangle.width = this.valueLimitInPercent;
- } else if (this.isBottom_()) {
- newMarginsRectangle.y = 0;
- newMarginsRectangle.height = this.valueLimitInPercent;
- }
-
- this.rectangle = this.getCoordinates_(newMarginsRectangle);
- this.drawDraggableArea_();
- }
- };
-
- return {
- MarginsUIPair: MarginsUIPair
- };
-});
diff --git a/chrome/browser/resources/print_preview/more_options.html b/chrome/browser/resources/print_preview/more_options.html
deleted file mode 100644
index c6032554..0000000
--- a/chrome/browser/resources/print_preview/more_options.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<div id="more-options" class="two-column visible">
- <h1 i18n-content="optionsLabel"></h1>
- <div class="right-column">
- <div id="header-footer-option">
- <label>
- <input id="header-footer" type="checkbox" checked>
- <span i18n-content="optionHeaderFooter"></span>
- </label>
- </div>
- <div id="fit-to-page-option">
- <label>
- <input id="fit-to-page" type="checkbox" checked>
- <span i18n-content="optionFitToPage"></span>
- </label>
- </div>
- </div>
-</div>
diff --git a/chrome/browser/resources/print_preview/more_options.js b/chrome/browser/resources/print_preview/more_options.js
deleted file mode 100644
index 68957af..0000000
--- a/chrome/browser/resources/print_preview/more_options.js
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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 MoreOptions object. This object encapsulates all
- * settings and logic related to the more options section.
- * @constructor
- */
- function MoreOptions() {
- // @type {HTMLDivElement} HTML element representing more options.
- this.moreOptions_ = $('more-options');
-
- // @type {boolean} True if header footer option is hidden.
- this.hideHeaderFooterOption_ = true;
-
- // @type {boolean} True if fit to page option should be hidden.
- this.hideFitToPageOption_ = true;
-
- this.addEventListeners_();
- }
-
- cr.addSingletonGetter(MoreOptions);
-
- MoreOptions.prototype = {
- /**
- * Adding listeners to more options section.
- * @private
- */
- addEventListeners_: function() {
- document.addEventListener(customEvents.PDF_LOADED,
- this.onPDFLoaded_.bind(this));
- document.addEventListener(
- customEvents.HEADER_FOOTER_VISIBILITY_CHANGED,
- this.onHeaderFooterVisibilityChanged_.bind(this));
- document.addEventListener(customEvents.PRINTER_SELECTION_CHANGED,
- this.onPrinterSelectionChanged_.bind(this));
- },
-
- /**
- * Listener executing when a |customEvents.HEADER_FOOTER_VISIBILITY_CHANGED|
- * event occurs.
- * @param {cr.Event} event The event that triggered this listener.
- * @private
- */
- onHeaderFooterVisibilityChanged_: function(event) {
- this.hideHeaderFooterOption_ = !event.headerFooterApplies;
- this.updateVisibility_();
- },
-
- /**
- * Listener executing when a |customEvents.PRINTER_SEELCTION_CHANGED| event
- * occurs.
- * @param {cr.Event} event The event that triggered this listener.
- * @private
- */
- onPrinterSelectionChanged_: function(event) {
- if (previewModifiable)
- return;
- this.hideFitToPageOption_ = event.selectedPrinter == PRINT_TO_PDF;
- this.updateVisibility_();
- },
-
- /**
- * Listener executing when a |customEvents.PDF_LOADED| event occurs.
- * @private
- */
- onPDFLoaded_: function() {
- if (previewModifiable)
- this.hideHeaderFooterOption_ = false;
- else
- this.hideFitToPageOption_ = false;
- },
-
- /**
- * Hides or shows |this.moreOptions_|.
- * @private
- */
- updateVisibility_: function() {
- if (this.hideFitToPageOption_ && this.hideHeaderFooterOption_)
- fadeOutOption(this.moreOptions_);
- else
- fadeInOption(this.moreOptions_);
- }
- };
-
- return {
- MoreOptions: MoreOptions
- };
-});
diff --git a/chrome/browser/resources/print_preview/native_layer.js b/chrome/browser/resources/print_preview/native_layer.js
new file mode 100644
index 0000000..8acec69
--- /dev/null
+++ b/chrome/browser/resources/print_preview/native_layer.js
@@ -0,0 +1,727 @@
+// 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';
+
+ /**
+ * An interface to the native Chromium printing system layer.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+ function NativeLayer() {
+ cr.EventTarget.call(this);
+
+ // Bind global handlers
+ global['setInitialSettings'] = this.onSetInitialSettings_.bind(this);
+ global['setUseCloudPrint'] = this.onSetUseCloudPrint_.bind(this);
+ global['setPrinters'] = this.onSetPrinters_.bind(this);
+ global['updateWithPrinterCapabilities'] =
+ this.onUpdateWithPrinterCapabilities_.bind(this);
+ global['reloadPrintersList'] = this.onReloadPrintersList_.bind(this);
+ global['printToCloud'] = this.onPrintToCloud_.bind(this);
+ global['fileSelectionCancelled'] =
+ this.onFileSelectionCancelled_.bind(this);
+ global['fileSelectionCompleted'] =
+ this.onFileSelectionCompleted_.bind(this);
+ global['printPreviewFailed'] = this.onPrintPreviewFailed_.bind(this);
+ global['invalidPrinterSettings'] =
+ this.onInvalidPrinterSettings_.bind(this);
+ global['onDidGetDefaultPageLayout'] =
+ this.onDidGetDefaultPageLayout_.bind(this);
+ global['onDidGetPreviewPageCount'] =
+ this.onDidGetPreviewPageCount_.bind(this);
+ global['reloadPreviewPages'] = this.onReloadPreviewPages_.bind(this);
+ global['onDidPreviewPage'] = this.onDidPreviewPage_.bind(this);
+ global['updatePrintPreview'] = this.onUpdatePrintPreview_.bind(this);
+ global['printScalingDisabledForSourcePDF'] =
+ this.onPrintScalingDisabledForSourcePDF_.bind(this);
+ };
+
+ /**
+ * Event types dispatched from the Chromium native layer.
+ * @enum {string}
+ * @const
+ */
+ NativeLayer.EventType = {
+ CAPABILITIES_SET: 'print_preview.NativeLayer.CAPABILITIES_SET',
+ CLOUD_PRINT_ENABLE: 'print_preview.NativeLayer.CLOUD_PRINT_ENABLE',
+ DESTINATIONS_RELOAD: 'print_preview.NativeLayer.DESTINATIONS_RELOAD',
+ DISABLE_SCALING: 'print_preview.NativeLayer.DISABLE_SCALING',
+ FILE_SELECTION_CANCEL: 'print_preview.NativeLayer.FILE_SELECTION_CANCEL',
+ FILE_SELECTION_COMPLETE:
+ 'print_preview.NativeLayer.FILE_SELECTION_COMPLETE',
+ INITIAL_SETTINGS_SET: 'print_preview.NativeLayer.INITIAL_SETTINGS_SET',
+ LOCAL_DESTINATIONS_SET: 'print_preview.NativeLayer.LOCAL_DESTINATIONS_SET',
+ PAGE_COUNT_READY: 'print_preview.NativeLayer.PAGE_COUNT_READY',
+ PAGE_LAYOUT_READY: 'print_preview.NativeLayer.PAGE_LAYOUT_READY',
+ PAGE_PREVIEW_READY: 'print_preview.NativeLayer.PAGE_PREVIEW_READY',
+ PREVIEW_GENERATION_DONE:
+ 'print_preview.NativeLayer.PREVIEW_GENERATION_DONE',
+ PREVIEW_GENERATION_FAIL:
+ 'print_preview.NativeLayer.PREVIEW_GENERATION_FAIL',
+ PREVIEW_RELOAD: 'print_preview.NativeLayer.PREVIEW_RELOAD',
+ PRINT_TO_CLOUD: 'print_preview.NativeLayer.PRINT_TO_CLOUD',
+ SETTINGS_INVALID: 'print_preview.NativeLayer.SETTINGS_INVALID'
+ };
+
+ /**
+ * Constant values matching printing::DuplexMode enum.
+ * @enum {number}
+ */
+ NativeLayer.DuplexMode = {
+ SIMPLEX: 0,
+ LONG_EDGE: 1,
+ UNKNOWN_DUPLEX_MODE: -1
+ };
+
+ /**
+ * Enumeration of color modes used by Chromium.
+ * @enum {number}
+ * @private
+ */
+ NativeLayer.ColorMode_ = {
+ GRAY: 1,
+ COLOR: 2
+ };
+
+ NativeLayer.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ /** Gets the initial settings to initialize the print preview with. */
+ startGetInitialSettings: function() {
+ chrome.send('getInitialSettings');
+ },
+
+ /**
+ * Requests the system's local print destinations. A LOCAL_DESTINATIONS_SET
+ * event will be dispatched in response.
+ */
+ startGetLocalDestinations: function() {
+ chrome.send('getPrinters');
+ },
+
+ /**
+ * Requests the destination's printing capabilities. A CAPABILITIES_SET
+ * event will be dispatched in response.
+ * @param {string} destinationId ID of the destination.
+ */
+ startGetLocalDestinationCapabilities: function(destinationId) {
+ chrome.send('getPrinterCapabilities', [destinationId]);
+ },
+
+ /**
+ * Requests that a preview be generated. The following events may be
+ * dispatched in response:
+ * - PAGE_COUNT_READY
+ * - PAGE_LAYOUT_READY
+ * - PAGE_PREVIEW_READY
+ * - PREVIEW_GENERATION_DONE
+ * - PREVIEW_GENERATION_FAIL
+ * - PREVIEW_RELOAD
+ * @param {print_preview.Destination} destination Destination to print to.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
+ * state of the print ticket.
+ * @param {number} ID of the preview request.
+ */
+ startGetPreview: function(destination, printTicketStore, requestId) {
+ assert(printTicketStore.isTicketValidForPreview(),
+ 'Trying to generate preview when ticket is not valid');
+
+ var pageRanges = [];
+ if (requestId > 0 &&
+ !printTicketStore.isDocumentModifiable &&
+ printTicketStore.hasPageRangeCapability()) {
+ pageRanges = printTicketStore.getPageNumberSet().getPageRanges();
+ }
+
+ var ticket = {
+ 'pageRange': pageRanges, // pageRanges,
+ 'landscape': printTicketStore.isLandscapeEnabled(),
+ 'color': printTicketStore.isColorEnabled() ?
+ NativeLayer.ColorMode_.COLOR : NativeLayer.ColorMode_.GRAY,
+ 'headerFooterEnabled': printTicketStore.isHeaderFooterEnabled(),
+ 'marginsType': printTicketStore.getMarginsType(),
+ 'isFirstRequest': requestId == 0,
+ 'requestID': requestId,
+ 'previewModifiable': printTicketStore.isDocumentModifiable,
+ 'printToPDF':
+ destination != null &&
+ destination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
+ 'printWithCloudPrint': destination != null && !destination.isLocal,
+ 'deviceName': destination == null ? 'foo' : destination.id,
+ 'cloudPrintID': destination == null ? 'foo' : destination.id,
+ 'generateDraftData': printTicketStore.isDocumentModifiable,
+ 'fitToPageEnabled': printTicketStore.isFitToPageEnabled(),
+
+ // NOTE: Even though the following fields don't directly relate to the
+ // preview, they still need to be included.
+ 'duplex': printTicketStore.isDuplexEnabled() ?
+ NativeLayer.DuplexMode.LONG_EDGE : NativeLayer.DuplexMode.SIMPLEX,
+ 'copies': printTicketStore.getCopies(),
+ 'collate': printTicketStore.isCollateEnabled()
+ };
+
+ if (printTicketStore.hasMarginsCapability() &&
+ printTicketStore.getMarginsType() ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ var customMargins = printTicketStore.getCustomMargins();
+ var orientationEnum =
+ print_preview.ticket_items.CustomMargins.Orientation;
+ ticket['marginsCustom'] = {
+ 'marginTop': customMargins.get(orientationEnum.TOP),
+ 'marginRight': customMargins.get(orientationEnum.RIGHT),
+ 'marginBottom': customMargins.get(orientationEnum.BOTTOM),
+ 'marginLeft': customMargins.get(orientationEnum.LEFT)
+ };
+ }
+
+ chrome.send(
+ 'getPreview',
+ [JSON.stringify(ticket), -1, printTicketStore.isDocumentModifiable]);
+ },
+
+ /**
+ * Persists the selected destination and print ticket for the next print
+ * session.
+ * @param {!print_preview.Destination} destination Destination to save.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used for
+ * generating the serialized print ticket to persist.
+ */
+ startSaveDestinationAndTicket: function(destination, printTicketStore) {
+ chrome.send('saveLastPrinter', [destination.id, '' /*TODO(rltoscano)*/]);
+ },
+
+ /**
+ * Requests that the document be printed.
+ * @param {!print_preview.Destination} destination Destination to print to.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
+ * state of the print ticket.
+ * @param {print_preview.CloudPrintInterface} cloudPrintInterface Interface
+ * to Google Cloud Print.
+ * @param {boolean=} opt_isOpenPdfInPreview Whether to open the PDF in the
+ * system's preview application.
+ */
+ startPrint: function(destination, printTicketStore, cloudPrintInterface,
+ opt_isOpenPdfInPreview) {
+ assert(printTicketStore.isTicketValid(),
+ 'Trying to print when ticket is not valid');
+
+ var ticket = {
+ 'pageRange': printTicketStore.hasPageRangeCapability() ?
+ printTicketStore.getPageNumberSet().getPageRanges() : [],
+ 'landscape': printTicketStore.isLandscapeEnabled(),
+ 'color': printTicketStore.isColorEnabled() ?
+ NativeLayer.ColorMode_.COLOR : NativeLayer.ColorMode_.GRAY,
+ 'headerFooterEnabled': printTicketStore.isHeaderFooterEnabled(),
+ 'marginsType': printTicketStore.getMarginsType(),
+ 'generateDraftData': true, // TODO(rltoscano): What should this be?
+ 'duplex': printTicketStore.isDuplexEnabled() ?
+ NativeLayer.DuplexMode.LONG_EDGE : NativeLayer.DuplexMode.SIMPLEX,
+ 'copies': printTicketStore.getCopies(),
+ 'collate': printTicketStore.isCollateEnabled(),
+ 'previewModifiable': printTicketStore.isDocumentModifiable,
+ 'printToPDF': destination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
+ 'printWithCloudPrint': !destination.isLocal,
+ 'deviceName': destination.id,
+ 'isFirstRequest': false,
+ 'requestID': -1,
+ 'fitToPageEnabled': printTicketStore.isFitToPageEnabled()
+ };
+
+ if (!destination.isLocal && !destination.isPrintWithCloudPrint) {
+ // We can't set cloudPrintID if the destination is "Print with Cloud
+ // Print" because the native system will try to print to Google Cloud
+ // Print with this ID instead of opening a Google Cloud Print dialog.
+ ticket['cloudPrintID'] = destination.id;
+ }
+
+ if (printTicketStore.hasMarginsCapability() &&
+ printTicketStore.getMarginsType() ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ var customMargins = printTicketStore.getCustomMargins();
+ var orientationEnum =
+ print_preview.ticket_items.CustomMargins.Orientation;
+ ticket['marginsCustom'] = {
+ 'marginTop': customMargins.get(orientationEnum.TOP),
+ 'marginRight': customMargins.get(orientationEnum.RIGHT),
+ 'marginBottom': customMargins.get(orientationEnum.BOTTOM),
+ 'marginLeft': customMargins.get(orientationEnum.LEFT)
+ };
+ }
+
+ if (opt_isOpenPdfInPreview) {
+ ticket['OpenPDFInPreview'] = true;
+ }
+
+ var cloudTicket = null;
+ if (!destination.isLocal) {
+ assert(cloudPrintInterface != null,
+ 'Trying to print to a cloud destination but Google Cloud ' +
+ 'Print integration is disabled');
+ cloudTicket = cloudPrintInterface.createPrintTicket(
+ destination, printTicketStore);
+ cloudTicket = JSON.stringify(cloudTicket);
+ }
+
+ chrome.send('print', [JSON.stringify(ticket), cloudTicket]);
+ },
+
+ /** Requests that the current pending print request be cancelled. */
+ startCancelPendingPrint: function() {
+ chrome.send('cancelPendingPrintRequest');
+ },
+
+ /** Shows the system's native printing dialog. */
+ startShowSystemDialog: function() {
+ chrome.send('showSystemDialog');
+ },
+
+ /** Closes the print preview dialog. */
+ startCloseDialog: function() {
+ chrome.send('closePrintPreviewTab');
+ chrome.send('DialogClose');
+ },
+
+ /** Hide the print preview dialog and allow the native layer to close it. */
+ startHideDialog: function() {
+ chrome.send('hidePreview');
+ },
+
+ /**
+ * Opens the Google Cloud Print sign-in dialog. The DESTINATIONS_RELOAD
+ * event will be dispatched in response.
+ */
+ startCloudPrintSignIn: function() {
+ chrome.send('signIn');
+ },
+
+ /** Navigates the user to the system printer settings interface. */
+ startManageLocalPrinters: function() {
+ chrome.send('manageLocalPrinters');
+ },
+
+ /** Navigates the user to the Google Cloud Print management page. */
+ startManageCloudPrinters: function() {
+ chrome.send('manageCloudPrinters');
+ },
+
+ /**
+ * @param {object} initialSettings Object containing all initial settings.
+ */
+ onSetInitialSettings_: function(initialSettings) {
+ // TODO(rltoscano): Use initialSettings['cloudPrintData'] to prepopulate
+ // destination and initial print ticket.
+ var numberFormatSymbols =
+ print_preview.MeasurementSystem.parseNumberFormat(
+ initialSettings['numberFormat']);
+ var unitType = print_preview.MeasurementSystem.UnitType.IMPERIAL;
+ if (initialSettings['measurementSystem'] != null) {
+ unitType = initialSettings['measurementSystem'];
+ }
+ var measurementSystem = new print_preview.MeasurementSystem(
+ numberFormatSymbols[0],
+ numberFormatSymbols[1],
+ unitType);
+
+ var customMargins = null;
+ if (initialSettings.hasOwnProperty('marginTop') &&
+ initialSettings.hasOwnProperty('marginRight') &&
+ initialSettings.hasOwnProperty('marginBottom') &&
+ initialSettings.hasOwnProperty('marginLeft')) {
+ customMargins = new print_preview.Margins(
+ initialSettings['marginTop'] || 0,
+ initialSettings['marginRight'] || 0,
+ initialSettings['marginBottom'] || 0,
+ initialSettings['marginLeft'] || 0);
+ }
+
+ var marginsType = null;
+ if (initialSettings.hasOwnProperty('marginsType')) {
+ marginsType = initialSettings['marginsType'];
+ }
+
+ var nativeInitialSettings = new print_preview.NativeInitialSettings(
+ initialSettings['printAutomaticallyInKioskMode'] || false,
+ numberFormatSymbols[0] || ',',
+ numberFormatSymbols[1] || '.',
+ unitType,
+ initialSettings['previewModifiable'] || false,
+ marginsType,
+ customMargins,
+ initialSettings['duplex'] || false,
+ initialSettings['headerFooterEnabled'] || false,
+ initialSettings['printerName'] || null);
+
+ var initialSettingsSetEvent = new cr.Event(
+ NativeLayer.EventType.INITIAL_SETTINGS_SET);
+ initialSettingsSetEvent.initialSettings = nativeInitialSettings;
+ this.dispatchEvent(initialSettingsSetEvent);
+ },
+
+ /**
+ * Turn on the integration of Cloud Print.
+ * @param {string} cloudPrintURL The URL to use for cloud print servers.
+ * @private
+ */
+ onSetUseCloudPrint_: function(cloudPrintURL) {
+ var cloudPrintEnableEvent = new cr.Event(
+ NativeLayer.EventType.CLOUD_PRINT_ENABLE);
+ cloudPrintEnableEvent.baseCloudPrintUrl = cloudPrintURL;
+ this.dispatchEvent(cloudPrintEnableEvent);
+ },
+
+ /**
+ * Updates the print preview with local printers.
+ * Called from PrintPreviewHandler::SetupPrinterList().
+ * @param {Array} printers Array of printer info objects.
+ * @private
+ */
+ onSetPrinters_: function(printers) {
+ var localDestsSetEvent = new cr.Event(
+ NativeLayer.EventType.LOCAL_DESTINATIONS_SET);
+ localDestsSetEvent.destinationInfos = printers;
+ this.dispatchEvent(localDestsSetEvent);
+ },
+
+ /**
+ * Called when native layer gets settings information for a requested local
+ * destination.
+ * @param {Object} settingsInfo printer setting information.
+ * @private
+ */
+ onUpdateWithPrinterCapabilities_: function(settingsInfo) {
+ var capsSetEvent = new cr.Event(NativeLayer.EventType.CAPABILITIES_SET);
+ capsSetEvent.settingsInfo = settingsInfo;
+ this.dispatchEvent(capsSetEvent);
+ },
+
+ /** Reloads the printer list. */
+ onReloadPrintersList_: function() {
+ cr.dispatchSimpleEvent(this, NativeLayer.EventType.DESTINATIONS_RELOAD);
+ },
+
+ /**
+ * Called from the C++ layer.
+ * Take the PDF data handed to us and submit it to the cloud, closing the
+ * print preview tab once the upload is successful.
+ * @param {string} data Data to send as the print job.
+ * @private
+ */
+ onPrintToCloud_: function(data) {
+ var printToCloudEvent = new cr.Event(
+ NativeLayer.EventType.PRINT_TO_CLOUD);
+ printToCloudEvent.data = data;
+ this.dispatchEvent(printToCloudEvent);
+ },
+
+ /**
+ * Called from PrintPreviewUI::OnFileSelectionCancelled to notify the print
+ * preview tab regarding the file selection cancel event.
+ * @private
+ */
+ onFileSelectionCancelled_: function() {
+ cr.dispatchSimpleEvent(this, NativeLayer.EventType.FILE_SELECTION_CANCEL);
+ },
+
+ /**
+ * Called from PrintPreviewUI::OnFileSelectionCompleted to notify the print
+ * preview tab regarding the file selection completed event.
+ * @private
+ */
+ onFileSelectionCompleted_: function() {
+ // If the file selection is completed and the tab is not already closed it
+ // means that a pending print to pdf request exists.
+ cr.dispatchSimpleEvent(
+ this, NativeLayer.EventType.FILE_SELECTION_COMPLETE);
+ },
+
+ /**
+ * Display an error message when print preview fails.
+ * Called from PrintPreviewMessageHandler::OnPrintPreviewFailed().
+ * @private
+ */
+ onPrintPreviewFailed_: function() {
+ cr.dispatchSimpleEvent(
+ this, NativeLayer.EventType.PREVIEW_GENERATION_FAIL);
+ },
+
+ /**
+ * Display an error message when encountered invalid printer settings.
+ * Called from PrintPreviewMessageHandler::OnInvalidPrinterSettings().
+ * @private
+ */
+ onInvalidPrinterSettings_: function() {
+ cr.dispatchSimpleEvent(this, NativeLayer.EventType.SETTINGS_INVALID);
+ },
+
+ /**
+ * @param {{contentWidth: number, contentHeight: number, marginLeft: number,
+ * marginRight: number, marginTop: number, marginBottom: number,
+ * printableAreaX: number, printableAreaY: number,
+ * printableAreaWidth: number, printableAreaHeight: number}}
+ * pageLayout Specifies default page layout details in points.
+ * @param {boolean} hasCustomPageSizeStyle Indicates whether the previewed
+ * document has a custom page size style.
+ * @private
+ */
+ onDidGetDefaultPageLayout_: function(pageLayout, hasCustomPageSizeStyle) {
+ var pageLayoutChangeEvent = new cr.Event(
+ NativeLayer.EventType.PAGE_LAYOUT_READY);
+ pageLayoutChangeEvent.pageLayout = pageLayout;
+ pageLayoutChangeEvent.hasCustomPageSizeStyle = hasCustomPageSizeStyle;
+ this.dispatchEvent(pageLayoutChangeEvent);
+ },
+
+ /**
+ * Update the page count and check the page range.
+ * Called from PrintPreviewUI::OnDidGetPreviewPageCount().
+ * @param {number} pageCount The number of pages.
+ * @param {number} previewResponseId The preview request id that resulted in
+ * this response.
+ * @private
+ */
+ onDidGetPreviewPageCount_: function(pageCount, previewResponseId) {
+ var pageCountChangeEvent = new cr.Event(
+ NativeLayer.EventType.PAGE_COUNT_READY);
+ pageCountChangeEvent.pageCount = pageCount;
+ pageCountChangeEvent.previewResponseId = previewResponseId;
+ this.dispatchEvent(pageCountChangeEvent);
+ },
+
+ /**
+ * Called when no pipelining previewed pages.
+ * @param {string} previewUid Preview unique identifier.
+ * @param {number} previewResponseId The preview request id that resulted in
+ * this response.
+ * @private
+ */
+ onReloadPreviewPages_: function(previewUid, previewResponseId) {
+ var previewReloadEvent = new cr.Event(
+ NativeLayer.EventType.PREVIEW_RELOAD);
+ previewReloadEvent.previewUid = previewUid;
+ previewReloadEvent.previewResponseId = previewResponseId;
+ this.dispatchEvent(previewReloadEvent);
+ },
+
+ /**
+ * Notification that a print preview page has been rendered.
+ * Check if the settings have changed and request a regeneration if needed.
+ * Called from PrintPreviewUI::OnDidPreviewPage().
+ * @param {number} pageNumber The page number, 0-based.
+ * @param {string} previewUid Preview unique identifier.
+ * @param {number} previewResponseId The preview request id that resulted in
+ * this response.
+ * @private
+ */
+ onDidPreviewPage_: function(pageNumber, previewUid, previewResponseId) {
+ var pagePreviewGenEvent = new cr.Event(
+ NativeLayer.EventType.PAGE_PREVIEW_READY);
+ pagePreviewGenEvent.pageIndex = pageNumber;
+ pagePreviewGenEvent.previewUid = previewUid;
+ pagePreviewGenEvent.previewResponseId = previewResponseId;
+ this.dispatchEvent(pagePreviewGenEvent);
+ },
+
+ /**
+ * Update the print preview when new preview data is available.
+ * Create the PDF plugin as needed.
+ * Called from PrintPreviewUI::PreviewDataIsAvailable().
+ * @param {string} previewUid Preview unique identifier.
+ * @param {number} previewResponseId The preview request id that resulted in
+ * this response.
+ * @private
+ */
+ onUpdatePrintPreview_: function(previewUid, previewResponseId) {
+ var previewGenDoneEvent = new cr.Event(
+ NativeLayer.EventType.PREVIEW_GENERATION_DONE);
+ previewGenDoneEvent.previewUid = previewUid;
+ previewGenDoneEvent.previewResponseId = previewResponseId;
+ this.dispatchEvent(previewGenDoneEvent);
+ },
+
+ /**
+ * Updates the fit to page option state based on the print scaling option of
+ * source pdf. PDF's have an option to enable/disable print scaling. When we
+ * find out that the print scaling option is disabled for the source pdf, we
+ * uncheck the fitToPage_ to page checkbox. This function is called from C++
+ * code.
+ * @private
+ */
+ onPrintScalingDisabledForSourcePDF_: function() {
+ cr.dispatchSimpleEvent(this, NativeLayer.EventType.DISABLE_SCALING);
+ }
+ };
+
+ /**
+ * Initial settings retrieved from the native layer.
+ * @param {boolean} isInKioskAutoPrintMode Whether the print preview should be
+ * in auto-print mode.
+ * @param {string} thousandsDelimeter Character delimeter of thousands digits.
+ * @param {string} decimalDelimeter Character delimeter of the decimal point.
+ * @param {print_preview.MeasurementSystem.UnitType} unitType Unit type of
+ * local machine's measurement system.
+ * @param {boolean} isDocumentModifiable Whether the document to print is
+ * modifiable.
+ * @param {?print_preview.ticket_items.MarginsType.Value} marginsType Initial
+ * margins type.
+ * @param {print_preview.Margins} customMargins Initial custom margins.
+ * @param {boolean} isDuplexEnabled Whether duplexing is initially enabled.
+ * @param {boolean} isHeaderFooterEnabled Whether the header-footer is
+ * initially enabled.
+ * @param {?string} initialDestinationId ID of the destination to initially
+ * select.
+ * @constructor
+ */
+ function NativeInitialSettings(
+ isInKioskAutoPrintMode,
+ thousandsDelimeter,
+ decimalDelimeter,
+ unitType,
+ isDocumentModifiable,
+ marginsType,
+ customMargins,
+ isDuplexEnabled,
+ isHeaderFooterEnabled,
+ initialDestinationId) {
+
+ /**
+ * Whether the print preview should be in auto-print mode.
+ * @type {boolean}
+ * @private
+ */
+ this.isInKioskAutoPrintMode_ = isInKioskAutoPrintMode;
+
+ /**
+ * Character delimeter of thousands digits.
+ * @type {string}
+ * @private
+ */
+ this.thousandsDelimeter_ = thousandsDelimeter;
+
+ /**
+ * Character delimeter of the decimal point.
+ * @type {string}
+ * @private
+ */
+ this.decimalDelimeter_ = decimalDelimeter;
+
+ /**
+ * Unit type of local machine's measurement system.
+ * @type {string}
+ * @private
+ */
+ this.unitType_ = unitType;
+
+ /**
+ * Whether the document to print is modifiable.
+ * @type {boolean}
+ * @private
+ */
+ this.isDocumentModifiable_ = isDocumentModifiable;
+
+ /**
+ * Initial margins type.
+ * @type {?print_preview.ticket_items.MarginsType.Value}
+ * @private
+ */
+ this.marginsType_ = marginsType;
+
+ /**
+ * Initial custom margins.
+ * @type {print_preview.Margins}
+ * @private
+ */
+ this.customMargins_ = customMargins;
+
+ /**
+ * Whether duplexing is initially enabled.
+ * @type {boolean}
+ * @private
+ */
+ this.isDuplexEnabled_ = isDuplexEnabled;
+
+ /**
+ * Whether the header-footer is initially enabled.
+ * @type {boolean}
+ * @private
+ */
+ this.isHeaderFooterEnabled_ = isHeaderFooterEnabled;
+
+ /**
+ * ID of the initially selected destination.
+ * @type {?string}
+ * @private
+ */
+ this.initialDestinationId_ = initialDestinationId;
+ };
+
+ NativeInitialSettings.prototype = {
+ /**
+ * @return {boolean} Whether the print preview should be in auto-print mode.
+ */
+ get isInKioskAutoPrintMode() {
+ return this.isInKioskAutoPrintMode_;
+ },
+
+ /** @return {string} Character delimeter of thousands digits. */
+ get thousandsDelimeter() {
+ return this.thousandsDelimeter_;
+ },
+
+ /** @return {string} Character delimeter of the decimal point. */
+ get decimalDelimeter() {
+ return this.decimalDelimeter_;
+ },
+
+ /**
+ * @return {print_preview.MeasurementSystem.UnitType} Unit type of local
+ * machine's measurement system.
+ */
+ get unitType() {
+ return this.unitType_;
+ },
+
+ /** @return {boolean} Whether the document to print is modifiable. */
+ get isDocumentModifiable() {
+ return this.isDocumentModifiable_;
+ },
+
+ /**
+ * @return {?print_preview.ticket_items.MarginsType.Value} Initial margins
+ * type or {@code null} if not initially set.
+ */
+ get marginsType() {
+ return this.marginsType_;
+ },
+
+ /** @return {print_preview.Margins} Initial custom margins. */
+ get customMargins() {
+ return this.customMargins_;
+ },
+
+ /** @return {boolean} Whether duplexing is initially enabled. */
+ get isDuplexEnabled() {
+ return this.isDuplexEnabled_;
+ },
+
+ /** @return {boolean} Whether the header-footer is initially enabled. */
+ get isHeaderFooterEnabled() {
+ return this.isHeaderFooterEnabled_;
+ },
+
+ /** @return {?string} ID of the initially selected destination. */
+ get initialDestinationId() {
+ return this.initialDestinationId_;
+ }
+ };
+
+ // Export
+ return {
+ NativeInitialSettings: NativeInitialSettings,
+ NativeLayer: NativeLayer
+ };
+});
diff --git a/chrome/browser/resources/print_preview/page_settings.html b/chrome/browser/resources/print_preview/page_settings.html
deleted file mode 100644
index d4e55d2..0000000
--- a/chrome/browser/resources/print_preview/page_settings.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="two-column visible">
- <h1 i18n-content="pagesLabel"></h1>
- <div class="right-column">
- <div class="radio"><label>
- <input id="all-pages" name="pages" checked type="radio">
- <span i18n-content="optionAllPages"></span>
- </label></div>
- <div>
- <div id="print-pages-div">
- <input id="print-pages" name="pages" type="radio"
- i18n-values="aria-label:printPagesLabel;">
- <input id="individual-pages" type="text"
- i18n-values="placeholder:examplePageRangeText">
- </div>
- <span id="individual-pages-hint" class="hint"
- i18n-content="pageRangeInstruction" aria-hidden="true"
- aria-live="polite">
- </span>
- </div>
- </div>
-</div>
diff --git a/chrome/browser/resources/print_preview/page_settings.js b/chrome/browser/resources/print_preview/page_settings.js
deleted file mode 100644
index b03306c..0000000
--- a/chrome/browser/resources/print_preview/page_settings.js
+++ /dev/null
@@ -1,378 +0,0 @@
-// 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 PageSettings object. This object encapsulates all settings and
- * logic related to page selection.
- * @constructor
- */
- function PageSettings() {
- this.allPagesRadioButton_ = $('all-pages');
- this.selectedPagesRadioButton_ = $('print-pages');
- this.selectedPagesTextfield_ = $('individual-pages');
- this.selectedPagesHint_ = $('individual-pages-hint');
-
- // Timer id of |this.selectedPagesTextfield|. It is used to reset the timer
- // whenever needed.
- this.timerId_;
-
- // Contains the previously selected pages (pages requested by last
- // preview request). It is used in
- // |this.onSelectedPagesMayHaveChanged_()| to make sure that a new preview
- // is not requested more often than necessary.
- this.previouslySelectedPages_ = [];
-
- // The total page count of the previewed document regardless of which pages
- // the user has selected.
- this.totalPageCount_ = undefined;
- this.addEventListeners_();
- }
-
- cr.addSingletonGetter(PageSettings);
-
- PageSettings.prototype = {
- /**
- * The text that is currently in |this.selectedPagesTextfield|.
- * @type {string}
- */
- get selectedPagesText() {
- return this.selectedPagesTextfield_.value;
- },
-
- /**
- * The radio button corresponding to "all pages selected".
- * @type {HTMLInputElement}
- */
- get allPagesRadioButton() {
- return this.allPagesRadioButton_;
- },
-
- /**
- * The radio button corresponding to "specific pages selected".
- * @type {HTMLInputElement}
- */
- get selectedPagesRadioButton() {
- return this.selectedPagesRadioButton_;
- },
-
- /**
- * The textfield containing page ranges as specified by the user.
- * @type {HTMLInputElement}
- */
- get selectedPagesTextfield() {
- return this.selectedPagesTextfield_;
- },
-
- /**
- * The span element containing the hint shown to the user when page
- * selection is not valid.
- * @type {HTMLElement}
- */
- get selectedPagesHint() {
- return this.selectedPagesHint_;
- },
-
- /**
- * The total page count of the previewed document regardless of which pages
- * the user has selected. If the total count is not known this value must
- * be undefined.
- * @type {number}
- */
- get totalPageCount() {
- return this.totalPageCount_;
- },
-
- /**
- * @param {number} count The number to assing to |this.totalPageCount_|.
- */
- set totalPageCount(count) {
- this.totalPageCount_ = count;
- },
-
- /**
- * Returns the selected pages in ascending order without any duplicates.
- *
- * @return {Array.<number>} The selected pages.
- */
- get selectedPagesSet() {
- var selectedPagesText = this.selectedPagesText;
-
- if (this.allPagesRadioButton.checked || selectedPagesText.length == 0)
- selectedPagesText = '1-' + this.totalPageCount_;
-
- var pageList = pageRangeTextToPageList(selectedPagesText,
- this.totalPageCount_);
- return pageListToPageSet(pageList);
- },
-
- /**
- * Returns the previously selected pages in ascending order without any
- * duplicates.
- *
- * @return {Array.<number>} The previously selected pages.
- */
- get previouslySelectedPages() {
- return this.previouslySelectedPages_;
- },
-
- /**
- * Returns an array of objects describing the selected page ranges. See
- * documentation of pageSetToPageRanges() for more details.
- * @return {Array.<{from: number, to: number}>} An array of page range
- * objects.
- */
- get selectedPageRanges() {
- return pageSetToPageRanges(this.selectedPagesSet);
- },
-
- /**
- * Invalidates |this.totalPageCount_| to indicate that the total number of
- * pages is not known.
- * @private
- */
- invalidateTotalPageCount_: function() {
- this.totalPageCount_ = undefined;
- },
-
- /**
- * Invlidates |this.previouslySelectedPages_| to indicate that this value
- * does no longer apply.
- * @private
- */
- invalidatePreviouslySelectedPages_: function() {
- this.previouslySelectedPages_.length = 0;
- },
-
- /**
- * Resets all the state variables of this object and hides
- * |this.selectedPagesHint|.
- */
- resetState: function() {
- this.selectedPagesTextfield.classList.remove('invalid');
- fadeOutElement(this.selectedPagesHint_);
- this.invalidateTotalPageCount_();
- this.invalidatePreviouslySelectedPages_();
- },
-
- /**
- * Updates |this.totalPageCount_| and |this.previouslySelectedPages_|,
- * only if they have been previously invalidated.
- * @param {number} newTotalPageCount The new total page count.
- */
- updateState: function(newTotalPageCount) {
- if (!this.totalPageCount_)
- this.totalPageCount_ = newTotalPageCount;
-
- if (this.previouslySelectedPages_.length == 0) {
- for (var i = 0; i < this.totalPageCount_; i++)
- this.previouslySelectedPages_.push(i + 1);
- }
-
- if (!this.isPageSelectionValid())
- this.onSelectedPagesTextfieldChanged();
- },
-
- /**
- * Updates |this.previouslySelectedPages_| with the currently selected
- * pages.
- */
- updatePageSelection: function() {
- this.previouslySelectedPages_ = this.selectedPagesSet;
- },
-
- /**
- * @private
- * @return {boolean} true if currently selected pages differ from
- * |this.previouslySelectesPages_|.
- */
- hasPageSelectionChanged_: function() {
- return !areArraysEqual(this.previouslySelectedPages_,
- this.selectedPagesSet);
- },
-
- /**
- * Checks if the page selection has changed and is valid.
- * @return {boolean} true if the page selection is changed and is valid.
- */
- hasPageSelectionChangedAndIsValid: function() {
- return this.isPageSelectionValid() && this.hasPageSelectionChanged_();
- },
-
- /**
- * Validates the contents of |this.selectedPagesTextfield|.
- *
- * @return {boolean} true if the text is valid.
- */
- isPageSelectionValid: function() {
- if (this.allPagesRadioButton_.checked ||
- this.selectedPagesText.length == 0) {
- return true;
- }
- return isPageRangeTextValid(this.selectedPagesText, this.totalPageCount_);
- },
-
- /**
- * Checks all page selection related settings and requests a new print
- * previw if needed.
- * @return {boolean} true if a new preview was requested.
- */
- requestPrintPreviewIfNeeded: function() {
- if (this.hasPageSelectionChangedAndIsValid()) {
- this.updatePageSelection();
- requestPrintPreview();
- return true;
- }
- if (!this.isPageSelectionValid())
- this.onSelectedPagesTextfieldChanged();
- return false;
- },
-
- /**
- * Validates the selected pages and updates the hint accordingly.
- * @private
- */
- validateSelectedPages_: function() {
- if (this.isPageSelectionValid()) {
- this.selectedPagesTextfield.classList.remove('invalid');
- fadeOutElement(this.selectedPagesHint_);
- this.selectedPagesHint.setAttribute('aria-hidden', 'true');
- } else {
- this.selectedPagesTextfield.classList.add('invalid');
- this.selectedPagesHint.classList.remove('suggestion');
- this.selectedPagesHint.setAttribute('aria-hidden', 'false');
- this.selectedPagesHint.innerHTML =
- localStrings.getStringF('pageRangeInstruction',
- localStrings.getString(
- 'examplePageRangeText'));
- fadeInElement(this.selectedPagesHint);
- }
- },
-
- /**
- * Executes whenever a blur event occurs on |this.selectedPagesTextfield|
- * or when the timer expires. It takes care of
- * 1) showing/hiding warnings/suggestions
- * 2) updating print button/summary
- */
- onSelectedPagesTextfieldChanged: function() {
- this.validateSelectedPages_();
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- },
-
- /**
- * When the user stops typing in |this.selectedPagesTextfield| or clicks on
- * |allPagesRadioButton|, 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 pages differ from |this.previouslySelectedPages_|.
- * @private
- */
- onSelectedPagesMayHaveChanged_: function() {
- if (this.selectedPagesRadioButton_.checked)
- this.onSelectedPagesTextfieldChanged();
-
- // Toggling between "all pages"/"some pages" radio buttons while having an
- // invalid entry in the page selection textfield still requires updating
- // the print summary and print button.
- if (!this.isPageSelectionValid() || !this.hasPageSelectionChanged_()) {
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- return;
- }
- requestPrintPreview();
- },
-
- /**
- * Whenever |this.selectedPagesTextfield| gains focus we add a timer to
- * detect when the user stops typing in order to update the print preview.
- * @private
- */
- addTimerToSelectedPagesTextfield_: function() {
- this.timerId_ = window.setTimeout(
- this.onSelectedPagesMayHaveChanged_.bind(this), 1000);
- },
-
- /**
- * As the user types in |this.selectedPagesTextfield|, we need to reset
- * this timer, since the page ranges are still being edited.
- * @private
- */
- resetSelectedPagesTextfieldTimer_: function() {
- clearTimeout(this.timerId_);
- this.addTimerToSelectedPagesTextfield_();
- },
-
- /**
- * Handles the blur event of |this.selectedPagesTextfield|. Un-checks
- * |this.selectedPagesRadioButton| if the input field is empty.
- * @private
- */
- onSelectedPagesTextfieldBlur_: function() {
- clearTimeout(this.timerId_);
- if (!this.selectedPagesText.length) {
- this.allPagesRadioButton_.checked = true;
- this.validateSelectedPages_();
- }
- this.onSelectedPagesMayHaveChanged_();
- },
-
- /**
- * Gives focus to |this.selectedPagesTextfield| when
- * |this.selectedPagesRadioButton| is clicked.
- * @private
- */
- onSelectedPagesRadioButtonChecked_: function() {
- this.selectedPagesTextfield_.focus();
- },
-
- /**
- * Listener executing when an input event occurs in
- * |this.selectedPagesTextfield|. Ensures that
- * |this.selectedPagesTextfield| is non-empty before checking
- * |this.selectedPagesRadioButton|.
- * @private
- */
- onSelectedPagesTextfieldInput_: function() {
- if (this.selectedPagesText.length)
- this.selectedPagesRadioButton.checked = true;
- this.resetSelectedPagesTextfieldTimer_();
- },
-
- /**
- * Listener executing whenever a keyup events occurs in the pages textfield.
- * @param {!KeyboardEvent} e The event that triggered this listener.
- * @private
- */
- onKeyUp_: function(e) {
- if (e.keyIdentifier == 'Enter')
- printHeader.onPrintRequested();
- },
-
- /**
- * Adding listeners to all pages related controls. The listeners take care
- * of altering their behavior depending on |hasPendingPreviewRequest|.
- * @private
- */
- addEventListeners_: function() {
- this.allPagesRadioButton.onclick =
- this.onSelectedPagesMayHaveChanged_.bind(this);
- this.selectedPagesRadioButton.onclick =
- this.onSelectedPagesMayHaveChanged_.bind(this);
- this.selectedPagesTextfield.oninput =
- this.onSelectedPagesTextfieldInput_.bind(this);
- this.selectedPagesTextfield.onfocus =
- this.addTimerToSelectedPagesTextfield_.bind(this);
- this.selectedPagesTextfield.onblur =
- this.onSelectedPagesTextfieldBlur_.bind(this);
- this.selectedPagesTextfield.onkeyup = this.onKeyUp_.bind(this);
- }
- };
-
- return {
- PageSettings: PageSettings
- };
-});
diff --git a/chrome/browser/resources/print_preview/preview_area.js b/chrome/browser/resources/print_preview/preview_area.js
deleted file mode 100644
index ed5e92c..0000000
--- a/chrome/browser/resources/print_preview/preview_area.js
+++ /dev/null
@@ -1,299 +0,0 @@
-// 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.
- * @constructor
- */
- function PreviewArea() {
- // The embedded pdf plugin object.
- this.pdfPlugin_ = null;
-
- // @type {HTMLDivElement} A layer on top of |this.pdfPlugin_| used for
- // displaying messages to the user.
- this.overlayLayer = $('overlay-layer');
- // @type {HTMLDivElement} Contains text displayed to the user followed by
- // three animated dots.
- this.customMessageWithDots_ = $('custom-message-with-dots');
- // @type {HTMLDivElement} Contains text displayed to the user.
- this.customMessage_ = $('custom-message');
- // @type {HTMLInputElement} Button associated with a displayed error
- // message.
- this.errorButton = $('error-button');
- // @type {HTMLDivElement} Contains three animated (dancing) dots.
- this.dancingDotsText = $('dancing-dots-text');
-
- // 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;
- // @type {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.
- this.pageLocationNormalized = null;
-
- // @type {EventTracker} Used to keep track of certain event listeners.
- this.eventTracker = new EventTracker();
-
- this.addEventListeners_();
- }
-
- 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 pdfPlugin() {
- return this.pdfPlugin_;
- },
-
- get pdfLoaded() {
- return this.pdfLoaded_;
- },
-
- set pdfLoaded(pdfLoaded) {
- this.pdfLoaded_ = pdfLoaded;
- },
-
- /**
- * Initializes the PDF plugin and places it on the page.
- * @param {!string} srcURL The URL of the document to be loaded in the
- * plugin.
- * @private
- */
- createPDFPlugin_: function(srcURL) {
- this.pdfPlugin_ = document.createElement('embed');
- this.pdfPlugin_.setAttribute('id', 'pdf-viewer');
- this.pdfPlugin_.setAttribute(
- 'type', 'application/x-google-chrome-print-preview-pdf');
- this.pdfPlugin_.setAttribute('src', srcURL);
- this.pdfPlugin_.setAttribute('aria-live', 'polite');
- this.pdfPlugin_.setAttribute('aria-atomic', 'true');
- $('mainview').appendChild(this.pdfPlugin_);
-
- this.pdfPlugin_.onload('onPDFLoad()');
- this.pdfPlugin_.onScroll('onPreviewPositionChanged()');
- this.pdfPlugin_.onPluginSizeChanged('onPreviewPositionChanged()');
- this.pdfPlugin_.removePrintButton();
- this.pdfPlugin_.grayscale(true);
- },
-
- /**
- * Reloads the plugin with a new url.
- * @param {string} srcURL The URL to load in the plugin.
- * @private
- */
- reloadPDFPlugin_: function(srcURL) {
- // Need to call this before the reload(), where the plugin resets its
- // internal page count.
- this.pdfPlugin_.goToPage('0');
- this.pdfPlugin_.resetPrintPreviewUrl(srcURL);
- this.pdfPlugin_.reload();
- this.pdfPlugin_.grayscale(
- colorSettings.colorMode == print_preview.ColorSettings.GRAY);
- },
-
- /**
- * Creates the PDF plugin or reloads the existing one.
- * @param {number} srcDataIndex Preview data source index.
- */
- createOrReloadPDFPlugin: function(srcDataIndex) {
- var srcURL = getPageSrcURL(currentPreviewUid, srcDataIndex);
- this.pdfPlugin_ ? this.reloadPDFPlugin_(srcURL) :
- this.createPDFPlugin_(srcURL);
- },
-
- /**
- * Queries the plugin for the location of the most visible page and updates
- * |this.pageLocationNormalized|.
- */
- update: function() {
- if (!this.pdfLoaded_)
- return;
- var pluginLocation =
- this.pdfPlugin_.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.pdfPlugin_ && previewModifiable) {
- 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(customEvents.PDF_LOADED,
- this.onPDFLoaded_.bind(this));
- },
-
- /**
- * Listener executing when a |customEvents.PDF_LOADED| 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();
- }
- },
-
- /**
- * Hides the |this.overlayLayer| and any messages currently displayed.
- */
- hideOverlayLayer: function() {
- this.eventTracker.add(this.overlayLayer, 'webkitTransitionEnd',
- this.hideOverlayLayerCleanup_.bind(this), false);
- if (this.pdfPlugin_)
- this.pdfPlugin_.classList.remove('invisible');
- this.overlayLayer.classList.add('invisible');
- },
-
- /**
- * Displays the "Preview loading..." animation.
- */
- showLoadingAnimation: function() {
- this.showCustomMessage(localStrings.getString('loading'));
- },
-
- /**
- * 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.eventTracker.remove(this.overlayLayer, 'webkitTransitionEnd');
- },
-
- /**
- * Displays |message| followed by three dancing dots animation.
- * @param {string} message The message to be displayed.
- */
- showCustomMessage: function(message) {
- this.customMessageWithDots_.innerHTML = message +
- this.dancingDotsText.innerHTML;
- this.customMessageWithDots_.hidden = false;
- if (this.pdfPlugin_)
- this.pdfPlugin_.classList.add('invisible');
- this.overlayLayer.classList.remove('invisible');
- },
-
- /**
- * Clears the custom message with dots animation.
- */
- clearCustomMessageWithDots: function() {
- this.customMessageWithDots_.innerHTML = '';
- this.customMessageWithDots_.hidden = true;
- },
-
- /**
- * Display an error message in the center of the preview area.
- * @param {string} errorMessage The error message to be displayed.
- */
- displayErrorMessageAndNotify: function(errorMessage) {
- this.overlayLayer.classList.remove('invisible');
- this.customMessage_.textContent = errorMessage;
- this.customMessage_.hidden = false;
- this.customMessageWithDots_.innerHTML = '';
- this.customMessageWithDots_.hidden = true;
- if (this.pdfPlugin_) {
- $('mainview').removeChild(this.pdfPlugin_);
- this.pdfPlugin_ = null;
- }
- cr.dispatchSimpleEvent(document, customEvents.PDF_GENERATION_ERROR);
- },
-
- /**
- * Display an error message in the center of the preview area followed by a
- * button.
- * @param {string} errorMessage The error message to be displayed.
- * @param {string} buttonText The text to be displayed within the button.
- * @param {string} buttonListener The listener to be executed when the
- * button is clicked.
- */
- displayErrorMessageWithButtonAndNotify: function(
- errorMessage, buttonText, buttonListener) {
- this.errorButton.disabled = false;
- this.errorButton.textContent = buttonText;
- this.errorButton.onclick = buttonListener;
- this.errorButton.hidden = false;
- $('system-dialog-throbber').hidden = true;
- $('native-print-dialog-throbber').hidden = true;
- if (cr.isMac)
- $('open-preview-app-throbber').hidden = true;
- this.displayErrorMessageAndNotify(errorMessage);
- }
- };
-
- return {
- PreviewArea: PreviewArea
- };
-});
diff --git a/chrome/browser/resources/print_preview/preview_generator.js b/chrome/browser/resources/print_preview/preview_generator.js
new file mode 100644
index 0000000..4787dc4
--- /dev/null
+++ b/chrome/browser/resources/print_preview/preview_generator.js
@@ -0,0 +1,392 @@
+// 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';
+
+ /**
+ * Interface to the Chromium print preview generator.
+ * @param {!print_preview.DestinationStore} destinationStore Used to get the
+ * currently selected destination.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to read the
+ * state of the ticket and write document information.
+ * @param {!print_preview.NativeLayer} nativeLayer Used to communicate to
+ * Chromium's preview rendering system.
+ * @constructor
+ * @extends {cr.EventTarget}
+ */
+ function PreviewGenerator(destinationStore, printTicketStore, nativeLayer) {
+ cr.EventTarget.call(this);
+
+ /**
+ * Used to get the currently selected destination.
+ * @type {!print_preview.DestinationStore}
+ * @private
+ */
+ this.destinationStore_ = destinationStore;
+
+ /**
+ * Used to read the state of the ticket and write document information.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+
+ /**
+ * Interface to the Chromium native layer.
+ * @type {!print_preview.NativeLayer}
+ * @private
+ */
+ this.nativeLayer_ = nativeLayer;
+
+ /**
+ * ID of current in-flight request. Requests that do not share this ID will
+ * be ignored.
+ * @type {number}
+ * @private
+ */
+ this.inFlightRequestId_ = -1;
+
+ /**
+ * Whether the previews are being generated in landscape mode.
+ * @type {boolean}
+ * @private
+ */
+ this.isLandscapeEnabled_ = false;
+
+ /**
+ * Whether the previews are being generated with a header and footer.
+ * @type {boolean}
+ * @private
+ */
+ this.isHeaderFooterEnabled_ = false;
+
+ /**
+ * Whether the previews are being generated in color.
+ * @type {boolean}
+ * @private
+ */
+ this.isColorEnabled_ = false;
+
+ /**
+ * Whether the document should be fitted to the page.
+ * @type {boolean}
+ * @private
+ */
+ this.isFitToPageEnabled_ = false;
+
+ /**
+ * Page number set used to generate the last preview.
+ * @type {print_preview.PageNumberSet}
+ * @private
+ */
+ this.pageNumberSet_ = null;
+
+ /**
+ * Margins type used to generate the last preview.
+ * @type {print_preview.ticket_items.MarginsType.Value}
+ * @private
+ */
+ this.marginsType_ = print_preview.ticket_items.MarginsType.Value.DEFAULT;
+
+ /**
+ * Destination that was selected for the last preview.
+ * @type {print_preview.Destination}
+ * @private
+ */
+ this.selectedDestination_ = null;
+
+ /**
+ * Event tracker used to keep track of native layer events.
+ * @type {!EventTracker}
+ * @private
+ */
+ this.tracker_ = new EventTracker();
+
+ this.addEventListeners_();
+ };
+
+ /**
+ * Event types dispatched by the preview generator.
+ * @enum {string}
+ */
+ PreviewGenerator.EventType = {
+ // Dispatched when the document can be printed.
+ DOCUMENT_READY: 'print_preview.PreviewGenerator.DOCUMENT_READY',
+
+ // Dispatched when a page preview is ready. The previewIndex field of the
+ // event is the index of the page in the modified document, not the
+ // original. So page 4 of the original document might be previewIndex = 0 of
+ // the modified document.
+ PAGE_READY: 'print_preview.PreviewGenerator.PAGE_READY',
+
+ // Dispatched when the document preview starts to be generated.
+ PREVIEW_START: 'print_preview.PreviewGenerator.PREVIEW_START',
+
+ // Dispatched when the current print preview request fails.
+ FAIL: 'print_preview.PreviewGenerator.FAIL'
+ };
+
+ PreviewGenerator.prototype = {
+ __proto__: cr.EventTarget.prototype,
+
+ /**
+ * Request that new preview be generated. A preview request will not be
+ * generated if the print ticket has not changed sufficiently.
+ * @return {boolean} Whether a new preview was actually requested.
+ */
+ requestPreview: function() {
+ if (!this.printTicketStore_.isTicketValidForPreview()) {
+ return false;
+ }
+ if (!this.hasPreviewChanged_()) {
+ // Changes to these ticket items might not trigger a new preview, but
+ // they still need to be recorded.
+ this.marginsType_ = this.printTicketStore_.getMarginsType();
+ return false;
+ }
+ this.isLandscapeEnabled_ = this.printTicketStore_.isLandscapeEnabled();
+ this.isHeaderFooterEnabled_ =
+ this.printTicketStore_.isHeaderFooterEnabled();
+ this.isColorEnabled_ = this.printTicketStore_.isColorEnabled();
+ this.isFitToPageEnabled_ = this.printTicketStore_.isFitToPageEnabled();
+ this.pageNumberSet_ = this.printTicketStore_.getPageNumberSet();
+ this.marginsType_ = this.printTicketStore_.getMarginsType();
+ this.selectedDestination_ = this.destinationStore_.selectedDestination;
+
+ this.inFlightRequestId_++;
+ this.nativeLayer_.startGetPreview(
+ this.destinationStore_.selectedDestination,
+ this.printTicketStore_,
+ this.inFlightRequestId_);
+ return true;
+ },
+
+ /** Removes all event listeners that the preview generator has attached. */
+ removeEventListeners: function() {
+ this.tracker_.removeAll();
+ },
+
+ /**
+ * Adds event listeners to the relevant native layer events.
+ * @private
+ */
+ addEventListeners_: function() {
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.PAGE_LAYOUT_READY,
+ this.onPageLayoutReady_.bind(this));
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.PAGE_COUNT_READY,
+ this.onPageCountReady_.bind(this));
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.PREVIEW_RELOAD,
+ this.onPreviewReload_.bind(this));
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.PAGE_PREVIEW_READY,
+ this.onPagePreviewReady_.bind(this));
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.PREVIEW_GENERATION_DONE,
+ this.onPreviewGenerationDone_.bind(this));
+ this.tracker_.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.PREVIEW_GENERATION_FAIL,
+ this.onPreviewGenerationFail_.bind(this));
+ },
+
+ /**
+ * Dispatches a PAGE_READY event to signal that a page preview is ready.
+ * @param {number} previewIndex Index of the page with respect to the pages
+ * shown in the preview. E.g an index of 0 is the first displayed page,
+ * but not necessarily the first original document page.
+ * @param {number} pageNumber Number of the page with respect to the
+ * document. A value of 3 means it's the third page of the original
+ * document.
+ * @param {string} previewUid Unique identifier of the preview.
+ * @private
+ */
+ dispatchPageReadyEvent_: function(previewIndex, pageNumber, previewUid) {
+ var pageGenEvent = new cr.Event(PreviewGenerator.EventType.PAGE_READY);
+ pageGenEvent.previewIndex = previewIndex;
+ pageGenEvent.previewUrl =
+ 'chrome://print/' + previewUid + '/' + (pageNumber - 1) +
+ '/print.pdf';
+ this.dispatchEvent(pageGenEvent);
+ },
+
+ /**
+ * Dispatches a PREVIEW_START event. Signals that the preview should be
+ * reloaded.
+ * @param {string} previewUid Unique identifier of the preview.
+ * @private
+ */
+ dispatchPreviewStartEvent_: function(previewUid) {
+ var previewStartEvent = new cr.Event(
+ PreviewGenerator.EventType.PREVIEW_START);
+ var index = -1;
+ if (this.printTicketStore_.isDocumentModifiable) {
+ index = 0;
+ }
+ previewStartEvent.previewUrl =
+ 'chrome://print/' + previewUid + '/' + index + '/print.pdf';
+ this.dispatchEvent(previewStartEvent);
+ },
+
+ /**
+ * @return {boolean} Whether the print ticket has changed sufficiently to
+ * determine whether a new preview request should be issued.
+ * @private
+ */
+ hasPreviewChanged_: function() {
+ var ticketStore = this.printTicketStore_;
+ return this.inFlightRequestId_ == -1 ||
+ ticketStore.isLandscapeEnabled() != this.isLandscapeEnabled_ ||
+ ticketStore.isHeaderFooterEnabled() != this.isHeaderFooterEnabled_ ||
+ ticketStore.isColorEnabled() != this.isColorEnabled_ ||
+ ticketStore.isFitToPageEnabled() != this.isFitToPageEnabled_ ||
+ !ticketStore.getPageNumberSet().equals(this.pageNumberSet_) ||
+ (ticketStore.getMarginsType() != this.marginsType_ &&
+ ticketStore.getMarginsType() !=
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) ||
+ (ticketStore.getMarginsType() ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM &&
+ !ticketStore.getCustomMargins().equals(
+ ticketStore.getDocumentMargins())) ||
+ (this.selectedDestination_ !=
+ this.destinationStore_.selectedDestination &&
+ (this.destinationStore_.selectedDestination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ||
+ this.selectedDestination_.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF));
+ },
+
+ /**
+ * Called when the page layout of the document is ready. Always occurs
+ * as a result of a preview request.
+ * @param {cr.Event} event Contains layout info about the document.
+ * @private
+ */
+ onPageLayoutReady_: function(event) {
+ // NOTE: A request ID is not specified, so assuming its for the current
+ // in-flight request.
+
+ var origin = new print_preview.Coordinate2d(
+ event.pageLayout.printableAreaX,
+ event.pageLayout.printableAreaY);
+ var size = new print_preview.Size(
+ event.pageLayout.printableAreaWidth,
+ event.pageLayout.printableAreaHeight);
+
+ var margins = new print_preview.Margins(
+ Math.round(event.pageLayout.marginTop),
+ Math.round(event.pageLayout.marginRight),
+ Math.round(event.pageLayout.marginBottom),
+ Math.round(event.pageLayout.marginLeft));
+
+ var o = print_preview.ticket_items.CustomMargins.Orientation;
+ var pageSize = new print_preview.Size(
+ event.pageLayout.contentWidth +
+ margins.get(o.LEFT) + margins.get(o.RIGHT),
+ event.pageLayout.contentHeight +
+ margins.get(o.TOP) + margins.get(o.BOTTOM));
+
+ this.printTicketStore_.updateDocumentPageInfo(
+ new print_preview.PrintableArea(origin, size),
+ pageSize,
+ event.hasCustomPageSizeStyle,
+ margins);
+ },
+
+ /**
+ * Called when the document page count is received from the native layer.
+ * Always occurs as a result of a preview request.
+ * @param {cr.Event} event Contains the document's page count.
+ * @private
+ */
+ onPageCountReady_: function(event) {
+ if (this.inFlightRequestId_ != event.previewResponseId) {
+ return; // Ignore old response.
+ }
+ this.printTicketStore_.updatePageCount(event.pageCount);
+ this.pageNumberSet_ = this.printTicketStore_.getPageNumberSet();
+ },
+
+ /**
+ * Called when the print preview should be reloaded.
+ * @param {cr.Event} event Contains the preview UID and request ID.
+ * @private
+ */
+ onPreviewReload_: function(event) {
+ if (this.inFlightRequestId_ != event.previewResponseId) {
+ return; // Ignore old response.
+ }
+ this.dispatchPreviewStartEvent_(event.previewUid);
+ var pageNumberSet = this.printTicketStore_.getPageNumberSet();
+ for (var i = 0; i < pageNumberSet.size; i++) {
+ var pageNumber = pageNumberSet.getPageNumberAt(i);
+ this.dispatchPageReadyEvent_(i, pageNumber, event.previewUid);
+ }
+ cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.DOCUMENT_READY);
+ },
+
+ /**
+ * Called when a page's preview has been generated. Dispatches a
+ * PAGE_READY event.
+ * @param {cr.Event} event Contains the page index and preview UID.
+ * @private
+ */
+ onPagePreviewReady_: function(event) {
+ if (this.inFlightRequestId_ != event.previewResponseId) {
+ return; // Ignore old response.
+ }
+ var pageNumber = event.pageIndex + 1;
+ if (this.printTicketStore_.getPageNumberSet().hasPageNumber(pageNumber)) {
+ var previewIndex = this.printTicketStore_.getPageNumberSet()
+ .getPageNumberIndex(pageNumber);
+ if (previewIndex == 0) {
+ this.dispatchPreviewStartEvent_(event.previewUid);
+ }
+ this.dispatchPageReadyEvent_(
+ previewIndex, pageNumber, event.previewUid);
+ }
+ },
+
+ /**
+ * Called when the preview generation is complete. Dispatches a
+ * DOCUMENT_READY event.
+ * @param {cr.Event} event Contains the preview UID and response ID.
+ * @private
+ */
+ onPreviewGenerationDone_: function(event) {
+ if (this.inFlightRequestId_ != event.previewResponseId) {
+ return; // Ignore old response.
+ }
+ // Dispatch a PREVIEW_START event since non-modifiable documents don't
+ // trigger PAGE_READY events.
+ if (!this.printTicketStore_.isDocumentModifiable) {
+ this.dispatchPreviewStartEvent_(event.previewUid);
+ }
+ cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.DOCUMENT_READY);
+ },
+
+ /**
+ * Called when the preview generation fails.
+ * @private
+ */
+ onPreviewGenerationFail_: function() {
+ // NOTE: No request ID is returned from Chromium so its assumed its the
+ // current one.
+ cr.dispatchSimpleEvent(this, PreviewGenerator.EventType.FAIL);
+ }
+ };
+
+ // Export
+ return {
+ PreviewGenerator: PreviewGenerator
+ };
+});
diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control.css b/chrome/browser/resources/print_preview/previewarea/margin_control.css
new file mode 100644
index 0000000..38c5834
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/margin_control.css
@@ -0,0 +1,91 @@
+/* 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.
+ */
+
+#preview-area .margin-control {
+ -webkit-transition: opacity 150ms linear;
+ position: absolute;
+}
+
+#preview-area .margin-control.invisible {
+ opacity: 0;
+ pointer-events: none;
+}
+
+#preview-area .margin-control.margin-control-top,
+#preview-area .margin-control.margin-control-bottom {
+ cursor: ns-resize;
+ padding: 8px 0;
+ width: 100%;
+}
+
+#preview-area .margin-control.margin-control-left,
+#preview-area .margin-control.margin-control-right {
+ cursor: ew-resize;
+ height: 100%;
+ padding: 0 8px;
+}
+
+#preview-area .margin-control.margin-control-disabled {
+ cursor: default;
+}
+
+#preview-area .margin-control-line {
+ border-color: rgb(64, 128, 250);
+ border-style: dashed;
+ border-width: 1px;
+}
+
+#preview-area .margin-control-disabled .margin-control-line {
+ border-color: gray;
+}
+
+#preview-area .margin-control-top .margin-control-line,
+#preview-area .margin-control-bottom .margin-control-line {
+ width: 100%;
+}
+
+#preview-area .margin-control-left .margin-control-line,
+#preview-area .margin-control-right .margin-control-line {
+ height: 100%;
+}
+
+#preview-area .margin-control-textbox {
+ background-color: #2a2a2a;
+ border: 1px solid #888;
+ box-sizing: border-box;
+ color: white;
+ cursor: auto;
+ font-family: arial;
+ font-size: 0.8em;
+ height: 25px;
+ padding: 5px 0;
+ position: absolute;
+ text-align: center;
+ width: 60px;
+}
+
+#preview-area .margin-control-textbox.invalid {
+ background-color: rgb(193, 27, 23);
+}
+
+#preview-area .margin-control-top .margin-control-textbox {
+ left: 50%;
+ top: 8px;
+}
+
+#preview-area .margin-control-right .margin-control-textbox {
+ right: 8px;
+ top: 50%;
+}
+
+#preview-area .margin-control-bottom .margin-control-textbox {
+ bottom: 8px;
+ right: 50%;
+}
+
+#preview-area .margin-control-left .margin-control-textbox {
+ bottom: 50%;
+ left: 8px;
+}
diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control.html b/chrome/browser/resources/print_preview/previewarea/margin_control.html
new file mode 100644
index 0000000..58bbdbab
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/margin_control.html
@@ -0,0 +1,6 @@
+<div id="margin-control-template"
+ class="margin-control invisible"
+ style="display: none;">
+ <div class="margin-control-line"></div>
+ <input class="margin-control-textbox" type="text"/>
+</div>
diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control.js b/chrome/browser/resources/print_preview/previewarea/margin_control.js
new file mode 100644
index 0000000..476371a
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/margin_control.js
@@ -0,0 +1,467 @@
+// 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';
+
+ /**
+ * Draggable control for setting a page margin.
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Orientation of the margin control that determines where the margin
+ * textbox will be placed.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function MarginControl(orientation) {
+ print_preview.Component.call(this);
+
+ /**
+ * Determines where the margin textbox will be placed.
+ * @type {print_preview.ticket_items.CustomMargins.Orientation}
+ * @private
+ */
+ this.orientation_ = orientation;
+
+ /**
+ * Position of the margin control in points.
+ * @type {number}
+ * @private
+ */
+ this.positionInPts_ = 0;
+
+ /**
+ * Page size of the document to print.
+ * @type {!print_preview.Size}
+ * @private
+ */
+ this.pageSize_ = new print_preview.Size(0, 0);
+
+ /**
+ * Amount to scale pixel values by to convert to pixel space.
+ * @type {number}
+ * @private
+ */
+ this.scaleTransform_ = 1;
+
+ /**
+ * Amount to translate values in pixel space.
+ * @type {!print_preview.Coordinate2d}
+ * @private
+ */
+ this.translateTransform_ = new print_preview.Coordinate2d(0, 0);
+
+ /**
+ * Position of the margin control when dragging starts.
+ * @type {print_preview.Coordinate2d}
+ * @private
+ */
+ this.marginStartPositionInPixels_ = null;
+
+ /**
+ * Position of the mouse when the dragging starts.
+ * @type {print_preview.Coordinate2d}
+ * @private
+ */
+ this.mouseStartPositionInPixels_ = null;
+
+ /**
+ * Processing timeout for the textbox.
+ * @type {Object}
+ * @private
+ */
+ this.textTimeout_ = null;
+
+ /**
+ * Value of the textbox when the timeout was started.
+ * @type {?string}
+ * @private
+ */
+ this.preTimeoutValue_ = null;
+
+ /**
+ * Textbox used to display and receive the value of the margin.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.textbox_ = null;
+
+ /**
+ * Element of the margin control line.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.marginLineEl_ = null;
+
+ /**
+ * Whether this margin control's textbox has keyboard focus.
+ * @type {boolean}
+ * @private
+ */
+ this.isFocused_ = false;
+
+ /**
+ * Whether the margin control is in an error state.
+ * @type {boolean}
+ * @private
+ */
+ this.isInError_ = false;
+ };
+
+ /**
+ * Event types dispatched by the margin control.
+ * @enum {string}
+ */
+ MarginControl.EventType = {
+ // Dispatched when the margin control starts dragging.
+ DRAG_START: 'print_preview.MarginControl.DRAG_START',
+
+ // Dispatched when the text in the margin control's textbox changes.
+ TEXT_CHANGE: 'print_preview.MarginControl.TEXT_CHANGE'
+ };
+
+ /**
+ * CSS classes used by this component.
+ * @enum {string}
+ * @private
+ */
+ MarginControl.Classes_ = {
+ TOP: 'margin-control-top',
+ RIGHT: 'margin-control-right',
+ BOTTOM: 'margin-control-bottom',
+ LEFT: 'margin-control-left',
+ TEXTBOX: 'margin-control-textbox',
+ INVALID: 'invalid',
+ INVISIBLE: 'invisible',
+ DISABLED: 'margin-control-disabled',
+ DRAGGING: 'margin-control-dragging',
+ LINE: 'margin-control-line'
+ };
+
+ /**
+ * Map from orientation to CSS class name.
+ * @type {object.<
+ * print_preview.ticket_items.CustomMargins.Orientation,
+ * MarginControl.Classes_>}
+ * @private
+ */
+ MarginControl.OrientationToClass_ = {};
+ MarginControl.OrientationToClass_[
+ print_preview.ticket_items.CustomMargins.Orientation.TOP] =
+ MarginControl.Classes_.TOP;
+ MarginControl.OrientationToClass_[
+ print_preview.ticket_items.CustomMargins.Orientation.RIGHT] =
+ MarginControl.Classes_.RIGHT;
+ MarginControl.OrientationToClass_[
+ print_preview.ticket_items.CustomMargins.Orientation.BOTTOM] =
+ MarginControl.Classes_.BOTTOM;
+ MarginControl.OrientationToClass_[
+ print_preview.ticket_items.CustomMargins.Orientation.LEFT] =
+ MarginControl.Classes_.LEFT;
+
+ /**
+ * Radius of the margin control in pixels. Padding of control + 1 for border.
+ * @type {number}
+ * @const
+ * @private
+ */
+ MarginControl.RADIUS_ = 9;
+
+ /**
+ * Timeout after a text change after which the text in the textbox is saved to
+ * the print ticket. Value in milliseconds.
+ * @type {number}
+ * @const
+ * @private
+ */
+ MarginControl.TEXTBOX_TIMEOUT_ = 1000;
+
+ MarginControl.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ /** @return {boolean} Whether this margin control is in focus. */
+ getIsFocused: function() {
+ return this.isFocused_;
+ },
+
+ /**
+ * @return {print_preview.ticket_items.CustomMargins.Orientation}
+ * Orientation of the margin control.
+ */
+ getOrientation: function() {
+ return this.orientation_;
+ },
+
+ /**
+ * @param {number} scaleTransform New scale transform of the margin control.
+ */
+ setScaleTransform: function(scaleTransform) {
+ this.scaleTransform_ = scaleTransform;
+ // Reset position
+ this.setPositionInPts(this.positionInPts_);
+ },
+
+ /**
+ * @param {!print_preview.Coordinate2d} translateTransform New translate
+ * transform of the margin control.
+ */
+ setTranslateTransform: function(translateTransform) {
+ this.translateTransform_ = translateTransform;
+ // Reset position
+ this.setPositionInPts(this.positionInPts_);
+ },
+
+ /**
+ * @param {!print_preview.Size} pageSize New size of the document's pages.
+ */
+ setPageSize: function(pageSize) {
+ this.pageSize_ = pageSize;
+ this.setPositionInPts(this.positionInPts_);
+ },
+
+ /** @param {boolean} isVisible Whether the margin control is visible. */
+ setIsVisible: function(isVisible) {
+ if (isVisible) {
+ this.getElement().classList.remove(MarginControl.Classes_.INVISIBLE);
+ } else {
+ this.getElement().classList.add(MarginControl.Classes_.INVISIBLE);
+ }
+ },
+
+ /** @return {boolean} Whether the margin control is in an error state. */
+ getIsInError: function() {
+ return this.isInError_;
+ },
+
+ /**
+ * @param {boolean} isInError Whether the margin control is in an error
+ * state.
+ */
+ setIsInError: function(isInError) {
+ this.isInError_ = isInError;
+ if (isInError) {
+ this.textbox_.classList.add(MarginControl.Classes_.INVALID);
+ } else {
+ this.textbox_.classList.remove(MarginControl.Classes_.INVALID);
+ }
+ },
+
+ /** @param {boolean} isEnabled Whether to enable the margin control. */
+ setIsEnabled: function(isEnabled) {
+ this.textbox_.disabled = !isEnabled;
+ if (isEnabled) {
+ this.getElement().classList.remove(MarginControl.Classes_.DISABLED);
+ } else {
+ this.getElement().classList.add(MarginControl.Classes_.DISABLED);
+ }
+ },
+
+ /** @return {number} Current position of the margin control in points. */
+ getPositionInPts: function() {
+ return this.positionInPts_;
+ },
+
+ /**
+ * @param {number} posInPts New position of the margin control in points.
+ */
+ setPositionInPts: function(posInPts) {
+ this.positionInPts_ = posInPts;
+ var orientationEnum =
+ print_preview.ticket_items.CustomMargins.Orientation;
+ var x = this.translateTransform_.x;
+ var y = this.translateTransform_.y;
+ var width = null, height = null;
+ if (this.orientation_ == orientationEnum.TOP) {
+ y = this.scaleTransform_ * posInPts + this.translateTransform_.y -
+ MarginControl.RADIUS_;
+ width = this.scaleTransform_ * this.pageSize_.width;
+ } else if (this.orientation_ == orientationEnum.RIGHT) {
+ x = this.scaleTransform_ * (this.pageSize_.width - posInPts) +
+ this.translateTransform_.x - MarginControl.RADIUS_;
+ height = this.scaleTransform_ * this.pageSize_.height;
+ } else if (this.orientation_ == orientationEnum.BOTTOM) {
+ y = this.scaleTransform_ * (this.pageSize_.height - posInPts) +
+ this.translateTransform_.y - MarginControl.RADIUS_;
+ width = this.scaleTransform_ * this.pageSize_.width;
+ } else {
+ x = this.scaleTransform_ * posInPts + this.translateTransform_.x -
+ MarginControl.RADIUS_;
+ height = this.scaleTransform_ * this.pageSize_.height;
+ }
+ this.getElement().style.left = Math.round(x) + 'px';
+ this.getElement().style.top = Math.round(y) + 'px';
+ if (width != null) {
+ this.getElement().style.width = Math.round(width) + 'px';
+ }
+ if (height != null) {
+ this.getElement().style.height = Math.round(height) + 'px';
+ }
+ },
+
+ /** @return {string} The value in the margin control's textbox. */
+ getTextboxValue: function() {
+ return this.textbox_.value;
+ },
+
+ /** @param {string} value New value of the margin control's textbox. */
+ setTextboxValue: function(value) {
+ if (this.textbox_.value != value) {
+ this.textbox_.value = value;
+ }
+ },
+
+ /**
+ * Converts a value in pixels to points.
+ * @param {number} Pixel value to convert.
+ * @return {number} Given value expressed in points.
+ */
+ convertPixelsToPts: function(pixels) {
+ var pts;
+ var orientationEnum =
+ print_preview.ticket_items.CustomMargins.Orientation;
+ if (this.orientation_ == orientationEnum.TOP) {
+ pts = pixels - this.translateTransform_.y + MarginControl.RADIUS_;
+ pts /= this.scaleTransform_;
+ } else if (this.orientation_ == orientationEnum.RIGHT) {
+ pts = pixels - this.translateTransform_.x + MarginControl.RADIUS_;
+ pts /= this.scaleTransform_;
+ pts = this.pageSize_.width - pts;
+ } else if (this.orientation_ == orientationEnum.BOTTOM) {
+ pts = pixels - this.translateTransform_.y + MarginControl.RADIUS_;
+ pts /= this.scaleTransform_;
+ pts = this.pageSize_.height - pts;
+ } else {
+ pts = pixels - this.translateTransform_.x + MarginControl.RADIUS_;
+ pts /= this.scaleTransform_;
+ }
+ return pts;
+ },
+
+ /**
+ * Translates the position of the margin control relative to the mouse
+ * position in pixels.
+ * @param {!print_preview.Coordinate2d} mousePosition New position of
+ * the mouse.
+ * @return {!print_preview.Coordinate2d} New position of the margin control.
+ */
+ translateMouseToPositionInPixels: function(mousePosition) {
+ return new print_preview.Coordinate2d(
+ mousePosition.x - this.mouseStartPositionInPixels_.x +
+ this.marginStartPositionInPixels_.x,
+ mousePosition.y - this.mouseStartPositionInPixels_.y +
+ this.marginStartPositionInPixels_.y);
+ },
+
+ /** @override */
+ createDom: function() {
+ this.setElementInternal(this.cloneTemplateInternal(
+ 'margin-control-template'));
+ this.getElement().classList.add(MarginControl.OrientationToClass_[
+ this.orientation_]);
+ this.textbox_ = this.getElement().getElementsByClassName(
+ MarginControl.Classes_.TEXTBOX)[0];
+ this.marginLineEl_ = this.getElement().getElementsByClassName(
+ MarginControl.Classes_.LINE)[0];
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.tracker.add(
+ this.getElement(), 'mousedown', this.onMouseDown_.bind(this));
+ this.tracker.add(
+ this.textbox_, 'keydown', this.onTextboxKeyDown_.bind(this));
+ this.tracker.add(
+ this.textbox_, 'focus', this.setIsFocused_.bind(this, true));
+ this.tracker.add(this.textbox_, 'blur', this.onTexboxBlur_.bind(this));
+ },
+
+ /** @override */
+ exitDocument: function() {
+ print_preview.Component.prototype.exitDocument.call(this);
+ this.textbox_ = null;
+ this.marginLineEl_ = null;
+ },
+
+ /**
+ * @param {boolean} isFocused Whether the margin control is in focus.
+ * @private
+ */
+ setIsFocused_: function(isFocused) {
+ this.isFocused_ = isFocused;
+ },
+
+ /**
+ * Called whenever a mousedown event occurs on the component.
+ * @param {MouseEvent} event The event that occured.
+ * @private
+ */
+ onMouseDown_: function(event) {
+ if (!this.textbox_.disabled &&
+ event.button == 0 &&
+ (event.target == this.getElement() ||
+ event.target == this.marginLineEl_)) {
+ this.mouseStartPositionInPixels_ =
+ new print_preview.Coordinate2d(event.x, event.y);
+ this.marginStartPositionInPixels_ = new print_preview.Coordinate2d(
+ this.getElement().offsetLeft, this.getElement().offsetTop);
+ this.setIsInError(false);
+ cr.dispatchSimpleEvent(this, MarginControl.EventType.DRAG_START);
+ }
+ },
+
+ /**
+ * Called when a key down event occurs on the textbox. Dispatches a
+ * TEXT_CHANGE event if the "Enter" key was pressed.
+ * @param {Event} event Contains the key that was pressed.
+ * @private
+ */
+ onTextboxKeyDown_: function(event) {
+ if (this.textTimeout_) {
+ clearTimeout(this.textTimeout_);
+ this.textTimeout_ = null;
+ }
+ if (event.keyIdentifier == 'Enter') {
+ this.preTimeoutValue_ = null;
+ cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE);
+ } else {
+ if (this.preTimeoutValue_ == null) {
+ this.preTimeoutValue_ = this.textbox_.value;
+ }
+ this.textTimeout_ = setTimeout(
+ this.onTextboxTimeout_.bind(this), MarginControl.TEXTBOX_TIMEOUT_);
+ }
+ },
+
+ /**
+ * Called after a timeout after the text in the textbox has changed. Saves
+ * the textbox's value to the print ticket.
+ * @private
+ */
+ onTextboxTimeout_: function() {
+ this.textTimeout_ = null;
+ if (this.textbox_.value != this.preTimeoutValue_) {
+ cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE);
+ }
+ this.preTimeoutValue_ = null;
+ },
+
+ /**
+ * Called when the textbox loses focus. Dispatches a TEXT_CHANGE event.
+ */
+ onTexboxBlur_: function() {
+ if (this.textTimeout_) {
+ clearTimeout(this.textTimeout_);
+ this.textTimeout_ = null;
+ this.preTimeoutValue_ = null;
+ }
+ this.setIsFocused_(false);
+ cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE);
+ }
+ };
+
+ // Export
+ return {
+ MarginControl: MarginControl
+ };
+});
diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control_container.css b/chrome/browser/resources/print_preview/previewarea/margin_control_container.css
new file mode 100644
index 0000000..bfb1935
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/margin_control_container.css
@@ -0,0 +1,12 @@
+/* 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.
+ */
+
+.margin-control-container-dragging-vertical {
+ cursor: ns-resize;
+}
+
+.margin-control-container-dragging-horizontal {
+ cursor: ew-resize;
+}
diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control_container.js b/chrome/browser/resources/print_preview/previewarea/margin_control_container.js
new file mode 100644
index 0000000..1209da9
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/margin_control_container.js
@@ -0,0 +1,446 @@
+// 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';
+
+ /**
+ * UI component used for setting custom print margins.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to read and
+ * write custom margin values.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function MarginControlContainer(printTicketStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to read and write custom margin values.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+
+ /**
+ * Used to convert between the system's local units and points.
+ * @type {!print_preview.MeasurementSystem}
+ * @private
+ */
+ this.measurementSystem_ = printTicketStore.measurementSystem;
+
+ /**
+ * Convenience array that contains all of the margin controls.
+ * @type {!Object<
+ * print_preview.ticket_items.CustomMargins.Orientation,
+ * !print_preview.MarginControl>}
+ * @private
+ */
+ this.controls_ = {};
+ for (var key in print_preview.ticket_items.CustomMargins.Orientation) {
+ var orientation = print_preview.ticket_items.CustomMargins.Orientation[
+ key];
+ var control = new print_preview.MarginControl(orientation);
+ this.controls_[orientation] = control;
+ this.addChild(control);
+ }
+
+ /**
+ * Margin control currently being dragged. Null if no control is being
+ * dragged.
+ * @type {print_preview.MarginControl}
+ * @private
+ */
+ this.draggedControl_ = null;
+
+ /**
+ * Translation transformation in pixels to translate from the origin of the
+ * custom margins component to the top-left corner of the most visible
+ * preview page.
+ * @type {!print_preview.Coordinate2d}
+ * @private
+ */
+ this.translateTransform_ = new print_preview.Coordinate2d(0, 0);
+
+ /**
+ * Scaling transformation to scale from pixels to the units which the
+ * print preview is in. The scaling factor is the same in both dimensions,
+ * so this field is just a single number.
+ * @type {number}
+ * @private
+ */
+ this.scaleTransform_ = 1;
+
+ /**
+ * Clipping size for clipping the margin controls.
+ * @type {print_preview.Size}
+ * @private
+ */
+ this.clippingSize_ = null;
+ };
+
+ /**
+ * CSS classes used by the custom margins component.
+ * @enum {string}
+ * @private
+ */
+ MarginControlContainer.Classes_ = {
+ DRAGGING_HORIZONTAL: 'margin-control-container-dragging-horizontal',
+ DRAGGING_VERTICAL: 'margin-control-container-dragging-vertical'
+ };
+
+ /**
+ * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation
+ * Orientation value to test.
+ * @return {boolean} Whether the given orientation is TOP or BOTTOM.
+ * @private
+ */
+ MarginControlContainer.isTopOrBottom_ = function(orientation) {
+ return orientation ==
+ print_preview.ticket_items.CustomMargins.Orientation.TOP ||
+ orientation ==
+ print_preview.ticket_items.CustomMargins.Orientation.BOTTOM;
+ };
+
+ MarginControlContainer.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ /**
+ * Updates the translation transformation that translates pixel values in
+ * the space of the HTML DOM.
+ * @param {print_preview.Coordinate2d} translateTransform Updated value of
+ * the translation transformation.
+ */
+ updateTranslationTransform: function(translateTransform) {
+ if (!translateTransform.equals(this.translateTransform_)) {
+ this.translateTransform_ = translateTransform;
+ for (var orientation in this.controls_) {
+ this.controls_[orientation].setTranslateTransform(translateTransform);
+ }
+ }
+ },
+
+ /**
+ * Updates the scaling transform that scales pixels values to point values.
+ * @param {number} scaleTransform Updated value of the scale transform.
+ */
+ updateScaleTransform: function(scaleTransform) {
+ if (scaleTransform != this.scaleTransform_) {
+ this.scaleTransform_ = scaleTransform;
+ for (var orientation in this.controls_) {
+ this.controls_[orientation].setScaleTransform(scaleTransform);
+ }
+ }
+ },
+
+ /**
+ * Clips margin controls to the given clip size in pixels.
+ * @param {print_preview.Size} Size to clip the margin controls to.
+ */
+ updateClippingMask: function(clipSize) {
+ if (!clipSize) {
+ return;
+ }
+ this.clippingSize_ = clipSize;
+ for (var orientation in this.controls_) {
+ var el = this.controls_[orientation].getElement();
+ el.style.clip = 'rect(' +
+ (-el.offsetTop) + 'px, ' +
+ (clipSize.width - el.offsetLeft) + 'px, ' +
+ (clipSize.height - el.offsetTop) + 'px, ' +
+ (-el.offsetLeft) + 'px)';
+ }
+ },
+
+ /** Shows the margin controls if the need to be shown. */
+ showMarginControlsIfNeeded: function() {
+ if (this.printTicketStore_.getMarginsType() ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ this.setIsMarginControlsVisible_(true);
+ }
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+
+ // We want to respond to mouse up events even beyond the component's
+ // element.
+ this.tracker.add(window, 'mouseup', this.onMouseUp_.bind(this));
+ this.tracker.add(window, 'mousemove', this.onMouseMove_.bind(this));
+ this.tracker.add(
+ this.getElement(), 'mouseover', this.onMouseOver_.bind(this));
+ this.tracker.add(
+ this.getElement(), 'mouseout', this.onMouseOut_.bind(this));
+
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.INITIALIZE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.onTicketChange_.bind(this));
+
+ for (var orientation in this.controls_) {
+ this.tracker.add(
+ this.controls_[orientation],
+ print_preview.MarginControl.EventType.DRAG_START,
+ this.onControlDragStart_.bind(this, this.controls_[orientation]));
+ this.tracker.add(
+ this.controls_[orientation],
+ print_preview.MarginControl.EventType.TEXT_CHANGE,
+ this.onControlTextChange_.bind(this, this.controls_[orientation]));
+ }
+ },
+
+ /** @override */
+ decorateInternal: function() {
+ for (var orientation in this.controls_) {
+ this.controls_[orientation].render(this.getElement());
+ }
+ },
+
+ /**
+ * @param {boolean} isVisible Whether the margin controls are visible.
+ * @private
+ */
+ setIsMarginControlsVisible_: function(isVisible) {
+ for (var orientation in this.controls_) {
+ this.controls_[orientation].setIsVisible(isVisible);
+ }
+ },
+
+ /**
+ * Moves the position of the given control to the desired position in
+ * pixels within some constraint minimum and maximum.
+ * @param {!print_preview.MarginControl} control Control to move.
+ * @param {!print_preview.Coordinate2d} posInPixels Desired position to move
+ * to in pixels.
+ * @private
+ */
+ moveControlWithConstraints_: function(control, posInPixels) {
+ var newPosInPts;
+ if (MarginControlContainer.isTopOrBottom_(control.getOrientation())) {
+ newPosInPts = control.convertPixelsToPts(posInPixels.y);
+ } else {
+ newPosInPts = control.convertPixelsToPts(posInPixels.x);
+ }
+ newPosInPts = Math.min(
+ this.printTicketStore_.getCustomMarginMax(control.getOrientation()),
+ newPosInPts);
+ newPosInPts = Math.max(0, newPosInPts);
+ newPosInPts = Math.round(newPosInPts);
+ control.setPositionInPts(newPosInPts);
+ control.setTextboxValue(this.serializeValueFromPts_(newPosInPts));
+ },
+
+ /**
+ * @param {string} value Value to parse to points. E.g. '3.40"' or '200mm'.
+ * @return {number} Value in points represented by the input value.
+ * @private
+ */
+ parseValueToPts_: function(value) {
+ // Removing whitespace anywhere in the string.
+ value = value.replace(/\s*/g, '');
+ if (value.length == 0) {
+ return null;
+ }
+ var validationRegex = new RegExp('^(^-?)(\\d)+(\\' +
+ this.measurementSystem_.thousandsDelimeter + '\\d{3})*(\\' +
+ this.measurementSystem_.decimalDelimeter + '\\d*)?' +
+ '(' + this.measurementSystem_.unitSymbol + ')?$');
+ if (validationRegex.test(value)) {
+ // Replacing decimal point with the dot symbol in order to use
+ // parseFloat() properly.
+ var replacementRegex =
+ new RegExp('\\' + this.measurementSystem_.decimalDelimeter + '{1}');
+ value = value.replace(replacementRegex, '.');
+ return this.measurementSystem_.convertToPoints(parseFloat(value));
+ }
+ return null;
+ },
+
+ /**
+ * @param {number} value Value in points to serialize.
+ * @return {string} String representation of the value in the system's local
+ * units.
+ * @private
+ */
+ serializeValueFromPts_: function(value) {
+ value = this.measurementSystem_.convertFromPoints(value);
+ value = this.measurementSystem_.roundValue(value);
+ return value + this.measurementSystem_.unitSymbol;
+ },
+
+ /**
+ * Called when a margin control starts to drag.
+ * @param {print_preview.MarginControl} control The control which started to
+ * drag.
+ * @private
+ */
+ onControlDragStart_: function(control) {
+ this.draggedControl_ = control;
+ this.getElement().classList.add(
+ MarginControlContainer.isTopOrBottom_(control.getOrientation()) ?
+ MarginControlContainer.Classes_.DRAGGING_VERTICAL :
+ MarginControlContainer.Classes_.DRAGGING_HORIZONTAL);
+ },
+
+ /**
+ * Called when the mouse moves in the custom margins component. Moves the
+ * dragged margin control.
+ * @param {MouseEvent} event Contains the position of the mouse.
+ * @private
+ */
+ onMouseMove_: function(event) {
+ if (this.draggedControl_) {
+ this.moveControlWithConstraints_(
+ this.draggedControl_,
+ this.draggedControl_.translateMouseToPositionInPixels(
+ new print_preview.Coordinate2d(event.x, event.y)));
+ this.updateClippingMask(this.clippingSize_);
+ }
+ },
+
+ /**
+ * Called when the mouse is released in the custom margins component.
+ * Releases the dragged margin control.
+ * @param {MouseEvent} event Contains the position of the mouse.
+ * @private
+ */
+ onMouseUp_: function(event) {
+ if (this.draggedControl_) {
+ this.getElement().classList.remove(
+ MarginControlContainer.Classes_.DRAGGING_VERTICAL);
+ this.getElement().classList.remove(
+ MarginControlContainer.Classes_.DRAGGING_HORIZONTAL);
+ if (event) {
+ var posInPixels =
+ this.draggedControl_.translateMouseToPositionInPixels(
+ new print_preview.Coordinate2d(event.x, event.y));
+ this.moveControlWithConstraints_(this.draggedControl_, posInPixels);
+ }
+ this.updateClippingMask(this.clippingSize_);
+ this.printTicketStore_.updateCustomMargin(
+ this.draggedControl_.getOrientation(),
+ this.draggedControl_.getPositionInPts());
+ this.draggedControl_ = null;
+ }
+ },
+
+ /**
+ * Called when the mouse moves onto the component. Shows the margin
+ * controls.
+ * @private
+ */
+ onMouseOver_: function() {
+ var fromElement = event.fromElement;
+ while (fromElement != null) {
+ if (fromElement == this.getElement()) {
+ return;
+ }
+ fromElement = fromElement.parentElement;
+ }
+ if (this.printTicketStore_.hasMarginsCapability() &&
+ this.printTicketStore_.getMarginsType() ==
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ this.setIsMarginControlsVisible_(true);
+ }
+ },
+
+ /**
+ * Called when the mouse moves off of the component. Hides the margin
+ * controls.
+ * @private
+ */
+ onMouseOut_: function(event) {
+ var toElement = event.toElement;
+ while (toElement != null) {
+ if (toElement == this.getElement()) {
+ return;
+ }
+ toElement = toElement.parentElement;
+ }
+ if (this.draggedControl_ != null) {
+ return;
+ }
+ for (var orientation in this.controls_) {
+ if (this.controls_[orientation].getIsFocused() ||
+ this.controls_[orientation].getIsInError()) {
+ return;
+ }
+ }
+ this.setIsMarginControlsVisible_(false);
+ },
+
+ /**
+ * Called when the print ticket changes. Updates the position of the margin
+ * controls.
+ * @private
+ */
+ onTicketChange_: function() {
+ var margins = this.printTicketStore_.getCustomMargins();
+ for (var orientation in this.controls_) {
+ var control = this.controls_[orientation];
+ control.setPageSize(this.printTicketStore_.pageSize);
+ control.setTextboxValue(
+ this.serializeValueFromPts_(margins.get(orientation)));
+ control.setPositionInPts(margins.get(orientation));
+ control.setIsInError(false);
+ control.setIsEnabled(true);
+ }
+ this.updateClippingMask(this.clippingSize_);
+ if (this.printTicketStore_.getMarginsType() !=
+ print_preview.ticket_items.MarginsType.Value.CUSTOM) {
+ this.setIsMarginControlsVisible_(false);
+ }
+ },
+
+ /**
+ * Called when the text in a textbox of a margin control changes or the
+ * textbox loses focus.
+ * Updates the print ticket store.
+ * @param {!print_preview.MarginControl} control Updated control.
+ * @private
+ */
+ onControlTextChange_: function(control) {
+ var marginValue = this.parseValueToPts_(control.getTextboxValue());
+ if (marginValue != null) {
+ this.printTicketStore_.updateCustomMargin(
+ control.getOrientation(), marginValue);
+ } else {
+ var enableOtherControls;
+ if (!control.getIsFocused()) {
+ // If control no longer in focus, revert to previous valid value.
+ control.setTextboxValue(
+ this.serializeValueFromPts_(control.getPositionInPts()));
+ control.setIsInError(false);
+ enableOtherControls = true;
+ } else {
+ control.setIsInError(true);
+ enableOtherControls = false;
+ }
+ // Enable other controls.
+ for (var o in this.controls_) {
+ if (control.getOrientation() != o) {
+ this.controls_[o].setIsEnabled(enableOtherControls);
+ }
+ }
+ }
+ }
+ };
+
+ // Export
+ return {
+ MarginControlContainer: MarginControlContainer
+ };
+});
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.css b/chrome/browser/resources/print_preview/previewarea/preview_area.css
new file mode 100644
index 0000000..137f914
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.css
@@ -0,0 +1,75 @@
+/* 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.
+ */
+
+#preview-area.preview-area {
+ -webkit-box-flex: 1;
+ -webkit-user-select: none;
+ background-color: #ccc;
+ height: 100%;
+ overflow: hidden;
+ position: relative;
+}
+
+#preview-area .preview-area-plugin {
+ /* pluginFadeInTransitionDuration = 200ms */
+ -webkit-transition: opacity 200ms linear;
+ /* pluginFadeInTransitionDelay = overlayFadeOutTransitionDuration = 100ms */
+ -webkit-transition-delay: 100ms;
+ cursor: inherit;
+ height: 100%;
+ opacity: 1;
+ width: 100%;
+}
+
+#preview-area .preview-area-plugin.invisible {
+ /* pluginFadeOutTransitionDuration = 100ms */
+ -webkit-transition: opacity 100ms linear;
+ /* pluginFadeOutTransitionDelay = 250ms */
+ -webkit-transition-delay: 250ms;
+ opacity: 0;
+}
+
+#preview-area .preview-area-overlay-layer {
+ -webkit-transition: opacity 200ms linear;
+ /* overlayFadeInTransitionDelay = pluginFadeOutTransitionDelay +
+ * pluginFadeOutTransitionDuration = 350ms */
+ -webkit-transition-delay: 350ms;
+ -webkit-user-select: none;
+ background: #ccc;
+ height: 100%;
+ margin: 0;
+ opacity: 1;
+ position: absolute;
+ width: 100%;
+ z-index: 1;
+}
+
+#preview-area .preview-area-overlay-layer.invisible {
+ /* overlayFadeOutTransitionDuration = 100ms */
+ -webkit-transition: opacity 100ms linear;
+ opacity: 0;
+ pointer-events: none;
+}
+
+#preview-area .preview-area-messages {
+ height: 100%;
+}
+
+#preview-area .preview-area-message {
+ color: #404040;
+ font-size: 1.1em;
+ position: relative;
+ text-align: center;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .5);
+ top: 50%;
+}
+
+#preview-area .preview-area-no-plugin-action-area {
+ margin-top: 12px;
+}
+
+#preview-area .preview-area-open-system-dialog-button-throbber {
+ vertical-align: middle;
+}
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.html b/chrome/browser/resources/print_preview/previewarea/preview_area.html
new file mode 100644
index 0000000..39b9d81
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.html
@@ -0,0 +1,41 @@
+<div id="preview-area" class="preview-area">
+ <div class="preview-area-overlay-layer">
+ <div class="preview-area-messages">
+
+ <div class="preview-area-loading-message preview-area-message">
+ <span i18n-content="loading"></span>
+ <span class="preview-area-loading-message-jumping-dots jumping-dots"
+ ><span>.</span><span>.</span><span>.</span></span>
+ </div>
+
+ <div class="preview-area-custom-message preview-area-message"
+ style="display: none;">
+ <div class="preview-area-custom-message-text"></div>
+ <div class="preview-area-custom-action-area">
+ <button class="preview-area-open-system-dialog-button"
+ i18n-content="launchNativeDialog"></button>
+ <div class="preview-area-open-system-dialog-button-throbber throbber"
+ style="display: none;"></div>
+ </div>
+ </div>
+
+ <div class="preview-area-preview-failed-message preview-area-message"
+ i18n-content="previewFailed"
+ style="display: none;"></div>
+
+ <div class="preview-area-print-failed preview-area-message" style="display: none;">
+ <div i18n-content="invalidPrinterSettings"></div>
+ <div class="preview-area-print-failed-action-area">
+ <button class="preview-area-open-system-dialog-button"
+ i18n-content="launchNativeDialog"></button>
+ <div class="preview-area-open-system-dialog-button-throbber throbber"
+ style="display: none;"></div>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ <object class="preview-area-compatibility-object"
+ type="application/x-google-chrome-print-preview-pdf"
+ data="chrome://print/dummy.pdf"></object>
+</div>
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 0000000..1ede80a
--- /dev/null
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js
@@ -0,0 +1,592 @@
+// 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.DestinationStore} destinationStore Used to get the
+ * currently selected destination.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to get
+ * information about how the preview should be displayed.
+ * @param {!print_preview.NativeLayer} nativeLayer Needed to communicate with
+ * Chromium's preview generation system.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function PreviewArea(destinationStore, printTicketStore, nativeLayer) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to get the currently selected destination.
+ * @type {!print_preview.DestinationStore}
+ * @private
+ */
+ this.destinationStore_ = destinationStore;
+
+ /**
+ * Used to get information about how the preview should be displayed.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+
+ /**
+ * Used to contruct the preview generator.
+ * @type {!print_preview.NativeLayer}
+ * @private
+ */
+ this.nativeLayer_ = nativeLayer;
+
+ /**
+ * 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;
+
+ /**
+ * Custom margins component superimposed on the preview plugin.
+ * @type {!print_preview.MarginControlContainer}
+ * @private
+ */
+ this.marginControlContainer_ =
+ new print_preview.MarginControlContainer(this.printTicketStore_);
+ this.addChild(this.marginControlContainer_);
+
+ /**
+ * Current zoom level as a percentage.
+ * @type {?number}
+ * @private
+ */
+ this.zoomLevel_ = null;
+
+ /**
+ * Current page offset which can be used to calculate scroll amount.
+ * @type {print_preview.Coordinate2d}
+ * @private
+ */
+ this.pageOffset_ = null;
+
+ /**
+ * Whether the plugin has finished reloading.
+ * @type {boolean}
+ * @private
+ */
+ this.isPluginReloaded_ = false;
+
+ /**
+ * Whether the document preview is ready.
+ * @type {boolean}
+ * @private
+ */
+ this.isDocumentReady_ = false;
+
+ /**
+ * Timeout object used to display a loading message if the preview is taking
+ * a long time to generate.
+ * @type {Object}
+ * @private
+ */
+ this.loadingTimeout_ = null;
+
+ /**
+ * Overlay element.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.overlayEl_ = null;
+
+ /**
+ * The "Open system dialog" button.
+ * @type {HTMLButtonElement}
+ * @private
+ */
+ this.openSystemDialogButton_ = null;
+ };
+
+ /**
+ * Event types dispatched by the preview area.
+ * @enum {string}
+ */
+ PreviewArea.EventType = {
+ // Dispatched when the "Open system dialog" button is clicked.
+ OPEN_SYSTEM_DIALOG_CLICK:
+ 'print_preview.PreviewArea.OPEN_SYSTEM_DIALOG_CLICK',
+
+ // Dispatched when the document preview is complete.
+ PREVIEW_GENERATION_DONE:
+ 'print_preview.PreviewArea.PREVIEW_GENERATION_DONE',
+
+ // Dispatched when the document preview failed to be generated.
+ PREVIEW_GENERATION_FAIL:
+ 'print_preview.PreviewArea.PREVIEW_GENERATION_FAIL',
+
+ // Dispatched when a new document preview is being generated.
+ PREVIEW_GENERATION_IN_PROGRESS:
+ 'print_preview.PreviewArea.PREVIEW_GENERATION_IN_PROGRESS'
+ };
+
+ /**
+ * CSS classes used by the preview area.
+ * @enum {string}
+ * @private
+ */
+ PreviewArea.Classes_ = {
+ COMPATIBILITY_OBJECT: 'preview-area-compatibility-object',
+ CUSTOM_MESSAGE_TEXT: 'preview-area-custom-message-text',
+ MESSAGE: 'preview-area-message',
+ INVISIBLE: 'invisible',
+ 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'
+ };
+
+ /**
+ * Enumeration of IDs shown in the preview area.
+ * @enum {string}
+ * @private
+ */
+ PreviewArea.MessageId_ = {
+ CUSTOM: 'custom',
+ LOADING: 'loading',
+ PREVIEW_FAILED: 'preview-failed'
+ };
+
+ /**
+ * Maps message IDs to the CSS class that contains them.
+ * @type {object.<PreviewArea.MessageId_, string>}
+ * @private
+ */
+ PreviewArea.MessageIdClassMap_ = {};
+ PreviewArea.MessageIdClassMap_[PreviewArea.MessageId_.CUSTOM] =
+ 'preview-area-custom-message';
+ PreviewArea.MessageIdClassMap_[PreviewArea.MessageId_.LOADING] =
+ 'preview-area-loading-message';
+ PreviewArea.MessageIdClassMap_[PreviewArea.MessageId_.PREVIEW_FAILED] =
+ 'preview-area-preview-failed-message';
+
+ /**
+ * Amount of time in milliseconds to wait after issueing a new preview before
+ * the loading message is shown.
+ * @type {number}
+ * @const
+ * @private
+ */
+ PreviewArea.LOADING_TIMEOUT_ = 200;
+
+ 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;
+ },
+
+ /**
+ * Processes a keyboard event that could possibly be used to change state of
+ * the preview plugin.
+ * @param {MouseEvent} e Mouse event to process.
+ */
+ handleDirectionalKeyEvent: function(e) {
+ // Make sure the PDF plugin is there.
+ // We only care about: PageUp, PageDown, Left, Up, Right, Down.
+ // If the user is holding a modifier key, ignore.
+ if (!this.plugin_ ||
+ !arrayContains([33, 34, 37, 38, 39, 40], e.keyCode) ||
+ 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 = e.target;
+ while (element) {
+ if (element.scrollHeight > element.clientHeight ||
+ element.scrollWidth > element.clientWidth) {
+ 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();
+ },
+
+ /**
+ * Shows a custom message on the preview area's overlay.
+ * @param {string} message Custom message to show.
+ */
+ showCustomMessage: function(message) {
+ this.showMessage_(PreviewArea.MessageId_.CUSTOM, message);
+ },
+
+ /** @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.EventType.INITIALIZE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onTicketChange_.bind(this));
+
+ if (this.checkPluginCompatibility_()) {
+ this.previewGenerator_ = new print_preview.PreviewGenerator(
+ this.destinationStore_, this.printTicketStore_, this.nativeLayer_);
+ this.tracker.add(
+ this.previewGenerator_,
+ print_preview.PreviewGenerator.EventType.PREVIEW_START,
+ this.onPreviewStart_.bind(this));
+ this.tracker.add(
+ this.previewGenerator_,
+ print_preview.PreviewGenerator.EventType.PAGE_READY,
+ this.onPagePreviewReady_.bind(this));
+ this.tracker.add(
+ this.previewGenerator_,
+ print_preview.PreviewGenerator.EventType.FAIL,
+ this.onPreviewGenerationFail_.bind(this));
+ this.tracker.add(
+ this.previewGenerator_,
+ print_preview.PreviewGenerator.EventType.DOCUMENT_READY,
+ this.onDocumentReady_.bind(this));
+ } else {
+ this.showCustomMessage(localStrings.getString('noPlugin'));
+ }
+ },
+
+ /** @override */
+ exitDocument: function() {
+ print_preview.Component.prototype.exitDocument.call(this);
+ if (this.previewGenerator_) {
+ this.previewGenerator_.removeEventListeners();
+ }
+ this.overlayEl_ = null;
+ this.openSystemDialogButton_ = null;
+ },
+
+ /** @override */
+ decorateInternal: function() {
+ this.marginControlContainer_.decorate(this.getElement());
+ this.overlayEl_ = this.getElement().getElementsByClassName(
+ PreviewArea.Classes_.OVERLAY)[0];
+ this.openSystemDialogButton_ = 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;
+ },
+
+ /**
+ * Shows a given message on the overlay.
+ * @param {print_preview.PreviewArea.MessageId_} messageId ID of the message
+ * to show.
+ * @param {string=} opt_message Optional message to show that can be used
+ * by some message IDs.
+ * @private
+ */
+ showMessage_: function(messageId, opt_message) {
+ // Hide all messages.
+ var messageEls = this.getElement().getElementsByClassName(
+ PreviewArea.Classes_.MESSAGE);
+ for (var i = 0, messageEl; messageEl = messageEls[i]; i++) {
+ setIsVisible(messageEl, false);
+ }
+ // Disable jumping animation to conserve cycles.
+ var jumpingDotsEl = this.getElement().querySelector(
+ '.preview-area-loading-message-jumping-dots');
+ jumpingDotsEl.classList.remove('jumping-dots');
+
+ // Show specific message.
+ if (messageId == PreviewArea.MessageId_.CUSTOM) {
+ var customMessageTextEl = this.getElement().getElementsByClassName(
+ PreviewArea.Classes_.CUSTOM_MESSAGE_TEXT)[0];
+ customMessageTextEl.textContent = opt_message;
+ } else if (messageId == PreviewArea.MessageId_.LOADING) {
+ jumpingDotsEl.classList.add('jumping-dots');
+ }
+ var messageEl = this.getElement().getElementsByClassName(
+ PreviewArea.MessageIdClassMap_[messageId])[0];
+ setIsVisible(messageEl, true);
+
+ // Show overlay.
+ this.overlayEl_.classList.remove(PreviewArea.Classes_.INVISIBLE);
+ },
+
+ /**
+ * Hides the message overlay.
+ * @private
+ */
+ hideOverlay_: function() {
+ this.overlayEl_.classList.add(PreviewArea.Classes_.INVISIBLE);
+ // Disable jumping animation to conserve cycles.
+ var jumpingDotsEl = this.getElement().querySelector(
+ '.preview-area-loading-message-jumping-dots');
+ jumpingDotsEl.classList.remove('jumping-dots');
+ },
+
+ /**
+ * Creates a preview plugin and adds it to the DOM.
+ * @param {string} srcUrl Initial URL of the plugin.
+ * @private
+ */
+ createPlugin_: function(srcUrl) {
+ if (this.plugin_) {
+ console.warn('Pdf preview plugin already created');
+ return;
+ }
+ this.plugin_ = document.createElement('embed');
+ // NOTE: The plugin's 'id' field must be set to 'pdf-viewer' since
+ // chrome/renderer/print_web_view_helper.cc actually references it.
+ this.plugin_.setAttribute('id', 'pdf-viewer');
+ 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());
+ },
+
+ /**
+ * Dispatches a PREVIEW_GENERATION_DONE event if all conditions are met.
+ * @private
+ */
+ dispatchPreviewGenerationDoneIfReady_: function() {
+ if (this.isDocumentReady_ && this.isPluginReloaded_) {
+ cr.dispatchSimpleEvent(
+ this, PreviewArea.EventType.PREVIEW_GENERATION_DONE);
+ this.marginControlContainer_.showMarginControlsIfNeeded();
+ }
+ },
+
+ /**
+ * 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.EventType.OPEN_SYSTEM_DIALOG_CLICK);
+ },
+
+ /**
+ * Called when the print ticket changes. Updates the preview.
+ * @private
+ */
+ onTicketChange_: function() {
+ if (this.previewGenerator_ && this.previewGenerator_.requestPreview()) {
+ if (this.loadingTimeout_ == null) {
+ this.loadingTimeout_ = setTimeout(
+ this.showMessage_.bind(this, PreviewArea.MessageId_.LOADING),
+ PreviewArea.LOADING_TIMEOUT_);
+ }
+ } else {
+ this.marginControlContainer_.showMarginControlsIfNeeded();
+ }
+ },
+
+ /**
+ * Called when the preview generator begins loading the preview.
+ * @param {cr.Event} Contains the URL to initialize the plugin to.
+ * @private
+ */
+ onPreviewStart_: function(event) {
+ this.isDocumentReady_ = false;
+ this.isPluginReloaded_ = false;
+ if (!this.plugin_) {
+ this.createPlugin_(event.previewUrl);
+ }
+ this.plugin_.goToPage('0');
+ this.plugin_.resetPrintPreviewUrl(event.previewUrl);
+ this.plugin_.reload();
+ this.plugin_.grayscale(!this.printTicketStore_.isColorEnabled());
+ cr.dispatchSimpleEvent(
+ this, PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS);
+ },
+
+ /**
+ * Called when a page preview has been generated. Updates the plugin with
+ * the new page.
+ * @param {cr.Event} event Contains information about the page preview.
+ * @private
+ */
+ onPagePreviewReady_: function(event) {
+ this.plugin_.loadPreviewPage(event.previewUrl, event.previewIndex);
+ },
+
+ /**
+ * Called when the preview generation is complete and the document is ready
+ * to print.
+ * @private
+ */
+ onDocumentReady_: function(event) {
+ this.isDocumentReady_ = true;
+ this.dispatchPreviewGenerationDoneIfReady_();
+ },
+
+ /**
+ * Called when the generation of a preview fails. Shows an error message.
+ * @private
+ */
+ onPreviewGenerationFail_: function() {
+ this.showMessage_(PreviewArea.MessageId_.PREVIEW_FAILED);
+ cr.dispatchSimpleEvent(
+ this, PreviewArea.EventType.PREVIEW_GENERATION_FAIL);
+ },
+
+ /**
+ * Called when the plugin loads. This is a consequence of calling
+ * plugin.reload(). Certain plugin state can only be set after the plugin
+ * has loaded.
+ * @private
+ */
+ onPluginLoad_: function() {
+ if (this.loadingTimeout_) {
+ clearTimeout(this.loadingTimeout_);
+ this.loadingTimeout_ = null;
+ }
+ // Setting the plugin's page count can only be called after the plugin is
+ // loaded and the document must be modifiable.
+ if (this.printTicketStore_.isDocumentModifiable) {
+ this.plugin_.printPreviewPageCount(
+ this.printTicketStore_.getPageNumberSet().size);
+ }
+ this.plugin_.setPageNumbers(JSON.stringify(
+ this.printTicketStore_.getPageNumberSet().asArray()));
+ 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();
+ }
+ this.hideOverlay_();
+ this.isPluginReloaded_ = true;
+ this.dispatchPreviewGenerationDoneIfReady_();
+ },
+
+ /**
+ * Called when the preview plugin's visual state has changed. This is a
+ * consequence of scrolling or zooming the plugin. Updates the custom
+ * margins component if shown.
+ * @private
+ */
+ onPreviewVisualStateChange_: function() {
+ if (this.isPluginReloaded_) {
+ this.zoomLevel_ = this.plugin_.getZoomLevel();
+ this.pageOffset_ = new print_preview.Coordinate2d(
+ this.plugin_.pageXOffset(), this.plugin_.pageYOffset());
+ }
+ var normalized = this.plugin_.getPageLocationNormalized().split(';');
+ var pluginWidth = this.plugin_.getWidth();
+ var pluginHeight = this.plugin_.getHeight();
+ var translationTransform = new print_preview.Coordinate2d(
+ parseFloat(normalized[0]) * pluginWidth,
+ parseFloat(normalized[1]) * pluginHeight);
+ this.marginControlContainer_.updateTranslationTransform(
+ translationTransform);
+ var pageWidthInPixels = parseFloat(normalized[2]) * pluginWidth;
+ this.marginControlContainer_.updateScaleTransform(
+ pageWidthInPixels / this.printTicketStore_.pageSize.width);
+ this.marginControlContainer_.updateClippingMask(
+ new print_preview.Size(
+ pluginWidth - this.plugin_.getVerticalScrollbarThickness(),
+ pluginHeight - this.plugin_.getHorizontalScrollbarThickness()));
+ }
+ };
+
+ // Export
+ return {
+ PreviewArea: PreviewArea
+ };
+});
diff --git a/chrome/browser/resources/print_preview/print_header.css b/chrome/browser/resources/print_preview/print_header.css
new file mode 100644
index 0000000..dca74d3a
--- /dev/null
+++ b/chrome/browser/resources/print_preview/print_header.css
@@ -0,0 +1,15 @@
+/* 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.
+ */
+
+.print-header {
+ padding-bottom: 10px;
+ padding-top: 10px;
+}
+
+.print-header-summary {
+ color: rgb(83, 99, 125);
+ display: block;
+ min-height: 30px;
+}
diff --git a/chrome/browser/resources/print_preview/print_header.html b/chrome/browser/resources/print_preview/print_header.html
new file mode 100644
index 0000000..f0c3aeb
--- /dev/null
+++ b/chrome/browser/resources/print_preview/print_header.html
@@ -0,0 +1,10 @@
+<div id="print-header" class="print-header">
+ <span class="print-header-summary"></span>
+ <div class="button-strip">
+ <button class="print-header-print-button default"
+ i18n-content="printButton"
+ disabled></button>
+ <button class="print-header-cancel-button"
+ i18n-content="cancelButton"></button>
+ </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/print_header.js b/chrome/browser/resources/print_preview/print_header.js
index 6a74d04..2d93429 100644
--- a/chrome/browser/resources/print_preview/print_header.js
+++ b/chrome/browser/resources/print_preview/print_header.js
@@ -8,176 +8,232 @@ cr.define('print_preview', function() {
/**
* Creates a PrintHeader object. This object encapsulates all the elements
* and logic related to the top part of the left pane in print_preview.html.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to read
+ * information about the document.
+ * @param {!print_preview.DestinationStore} destinationStore Used to get the
+ * selected destination.
* @constructor
+ * @extends {print_preview.Component}
*/
- function PrintHeader() {
- this.printButton_ = $('print-button');
- this.cancelButton_ = $('cancel-button');
- this.summary_ = $('print-summary');
- this.printButton_.focus();
- this.addEventListeners_();
- }
-
- cr.addSingletonGetter(PrintHeader);
-
- PrintHeader.prototype = {
- get printButton() {
- return this.printButton_;
- },
-
- get cancelButton() {
- return this.cancelButton_;
- },
-
- get summary() {
- return this.summary_;
- },
+ function PrintHeader(printTicketStore, destinationStore) {
+ print_preview.Component.call(this);
/**
- * Adding event listeners where necessary. Listeners take care of changing
- * their behavior depending on the current state, no need to remove them.
+ * Used to read information about the document.
+ * @type {!print_preview.PrintTicketStore}
* @private
*/
- addEventListeners_: function() {
- this.cancelButton_.onclick = function() {
- this.disableCancelButton();
- closePrintPreviewTab();
- }.bind(this);
- this.printButton_.onclick = this.onPrintRequested.bind(this);
- document.addEventListener(customEvents.UPDATE_SUMMARY,
- this.updateSummary_.bind(this));
- document.addEventListener(customEvents.UPDATE_PRINT_BUTTON,
- this.updatePrintButton_.bind(this));
- document.addEventListener(customEvents.PDF_GENERATION_ERROR,
- this.onPDFGenerationError_.bind(this));
- document.addEventListener(customEvents.PRINTER_CAPABILITIES_UPDATED,
- this.onPrinterCapabilitiesUpdated_.bind(this));
- },
+ this.printTicketStore_ = printTicketStore;
/**
- * Enables the cancel button and attaches its keydown event listener.
+ * Used to get the selected destination.
+ * @type {!print_preview.DestinationStore}
+ * @private
*/
- enableCancelButton: function() {
- window.onkeydown = onKeyDown;
- this.cancelButton_.disabled = false;
- },
+ this.destinationStore_ = destinationStore;
/**
- * Executes when a |customEvents.PDF_GENERATION_ERROR| event occurs.
+ * Whether the component is enabled.
+ * @type {boolean}
* @private
*/
- onPDFGenerationError_: function() {
- this.printButton_.disabled = true;
+ this.isEnabled_ = true;
+ };
+
+ /**
+ * Event types dispatched by the print header.
+ * @enum {string}
+ */
+ PrintHeader.EventType = {
+ PRINT_BUTTON_CLICK: 'print_preview.PrintHeader.PRINT_BUTTON_CLICK',
+ CANCEL_BUTTON_CLICK: 'print_preview.PrintHeader.CANCEL_BUTTON_CLICK'
+ },
+
+ /**
+ * CSS classes used by the print header.
+ * @enum {string}
+ * @private
+ */
+ PrintHeader.Classes_ = {
+ CANCEL_BUTTON: 'print-header-cancel-button',
+ PRINT_BUTTON: 'print-header-print-button',
+ SUMMARY: 'print-header-summary'
+ };
+
+ PrintHeader.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ set isEnabled(isEnabled) {
+ this.isEnabled_ = isEnabled;
+ this.printButton_.disabled = !isEnabled;
+ this.cancelButton_.disabled = !isEnabled;
},
- /**
- * Executes when a |customEvents.PRINTER_CAPABILITIES_UPDATED| event occurs.
- * @private
- */
- onPrinterCapabilitiesUpdated_: function() {
- getSelectedPrinterName() == PRINT_TO_PDF ?
- this.printButton.textContent = localStrings.getString('saveButton') :
- this.printButton.textContent = localStrings.getString('printButton');
+ setErrorMessage: function(message) {
+ var summaryEl = this.getElement().getElementsByClassName(
+ PrintHeader.Classes_.SUMMARY)[0];
+ summaryEl.innerHTML = '';
+ summaryEl.textContent = message;
},
- /**
- * Disables the cancel button and removes its keydown event listener.
- */
- disableCancelButton: function() {
- window.onkeydown = null;
- this.cancelButton_.disabled = true;
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.printButton_.focus();
+
+ // User events
+ this.tracker.add(
+ this.cancelButton_, 'click', this.onCancelButtonClick_.bind(this));
+ this.tracker.add(
+ this.printButton_, 'click', this.onPrintButtonClick_.bind(this));
+
+ // Data events.
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.INITIALIZE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onTicketChange_.bind(this));
+ this.tracker.add(
+ this.destinationStore_,
+ print_preview.DestinationStore.EventType.DESTINATION_SELECT,
+ this.onDestinationSelect_.bind(this));
},
/**
- * Listener executing whenever the print button is clicked or user presses
- * the enter button while focus is in the pages field.
+ * @return {Element} Print button element.
+ * @private
*/
- onPrintRequested: function() {
- var printToPDF = getSelectedPrinterName() == PRINT_TO_PDF;
- if (!printToPDF) {
- this.printButton_.classList.add('loading');
- this.cancelButton_.classList.add('loading');
- this.summary_.innerHTML = localStrings.getString('printing');
- }
- this.disableCancelButton();
- requestToPrintDocument();
+ get printButton_() {
+ return this.getElement().getElementsByClassName(
+ PrintHeader.Classes_.PRINT_BUTTON)[0];
},
/**
- * Updates the state of |this.printButton_| depending on the user selection.
- * The button is enabled only when the following conditions are true.
- * 1) The selected page ranges are valid.
- * 2) The number of copies is valid (if applicable).
+ * @return {Element} Cancel button element.
* @private
*/
- updatePrintButton_: function() {
- if (showingSystemDialog)
- return;
- this.printButton_.disabled = !areSettingsValid();
+ get cancelButton_() {
+ return this.getElement().getElementsByClassName(
+ PrintHeader.Classes_.CANCEL_BUTTON)[0];
},
/**
- * Updates |this.summary_| based on the currently selected user options.
+ * Updates the summary element based on the currently selected user options.
* @private
*/
updateSummary_: function() {
- var printToPDF = getSelectedPrinterName() == PRINT_TO_PDF;
- var copies = printToPDF ? 1 : copiesSettings.numberOfCopies;
-
- if ((!printToPDF && !copiesSettings.isValid()) ||
- !pageSettings.isPageSelectionValid()) {
- this.summary_.innerHTML = '';
+ var summaryEl = this.getElement().getElementsByClassName(
+ PrintHeader.Classes_.SUMMARY)[0];
+ if (!this.printTicketStore_.isTicketValid()) {
+ summaryEl.innerHTML = '';
return;
}
- if (!marginSettings.areMarginSettingsValid()) {
- this.summary_.innerHTML = '';
- return;
- }
-
- var pageSet = pageSettings.selectedPagesSet;
- var numOfSheets = pageSet.length;
- if (numOfSheets == 0)
- return;
-
var summaryLabel =
localStrings.getString('printPreviewSheetsLabelSingular');
- var numOfPagesText = '';
var pagesLabel = localStrings.getString('printPreviewPageLabelPlural');
- if (printToPDF)
+ var saveToPdf = this.destinationStore_.selectedDestination &&
+ this.destinationStore_.selectedDestination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
+ if (saveToPdf) {
summaryLabel = localStrings.getString('printPreviewPageLabelSingular');
+ }
- if (!printToPDF &&
- copiesSettings.duplexMode == print_preview.CopiesSettings.LONG_EDGE) {
- numOfSheets = Math.ceil(numOfSheets / 2);
+ var numPages = this.printTicketStore_.getPageNumberSet().size;
+ var numSheets = numPages;
+ if (!saveToPdf && this.printTicketStore_.isDuplexEnabled()) {
+ numSheets = Math.ceil(numPages / 2);
}
- numOfSheets *= copies;
- if (numOfSheets > 1) {
- summaryLabel = printToPDF ? pagesLabel :
+ var copies = this.printTicketStore_.getCopies();
+ numSheets *= copies;
+ numPages *= copies;
+
+ if (numSheets > 1) {
+ summaryLabel = saveToPdf ? pagesLabel :
localStrings.getString('printPreviewSheetsLabelPlural');
}
- var html = '';
- if (pageSet.length * copies != numOfSheets) {
- numOfPagesText = pageSet.length * copies;
+ var html;
+ if (numPages != numSheets) {
html = localStrings.getStringF('printPreviewSummaryFormatLong',
- '<b>' + numOfSheets + '</b>',
+ '<b>' + numSheets + '</b>',
'<b>' + summaryLabel + '</b>',
- numOfPagesText, pagesLabel);
+ numPages,
+ pagesLabel);
} else {
html = localStrings.getStringF('printPreviewSummaryFormatShort',
- '<b>' + numOfSheets + '</b>',
+ '<b>' + numSheets + '</b>',
'<b>' + summaryLabel + '</b>');
}
// Removing extra spaces from within the string.
html = html.replace(/\s{2,}/g, ' ');
- this.summary_.innerHTML = html;
+ summaryEl.innerHTML = html;
+ },
+
+ /**
+ * Called when the print button is clicked. Dispatches a PRINT_DOCUMENT
+ * common event.
+ * @private
+ */
+ onPrintButtonClick_: function() {
+ if (this.destinationStore_.selectedDestination.id !=
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
+ this.printButton_.classList.add('loading');
+ this.cancelButton_.classList.add('loading');
+ var summaryEl = this.getElement().getElementsByClassName(
+ PrintHeader.Classes_.SUMMARY)[0];
+ summaryEl.innerHTML = localStrings.getString('printing');
+ }
+ cr.dispatchSimpleEvent(this, PrintHeader.EventType.PRINT_BUTTON_CLICK);
+ },
+
+ /**
+ * Called when the cancel button is clicked. Dispatches a
+ * CLOSE_PRINT_PREVIEW event.
+ * @private
+ */
+ onCancelButtonClick_: function() {
+ cr.dispatchSimpleEvent(this, PrintHeader.EventType.CANCEL_BUTTON_CLICK);
+ },
+
+ /**
+ * Called when a new destination is selected. Updates the text on the print
+ * button.
+ * @private
+ */
+ onDestinationSelect_: function() {
+ if (this.destinationStore_.selectedDestination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
+ this.printButton_.textContent = localStrings.getString('saveButton');
+ } else {
+ this.printButton_.textContent = localStrings.getString('printButton');
+ }
+ },
+
+ /**
+ * Called when the print ticket has changed. Disables the print button if
+ * any of the settings are invalid.
+ * @private
+ */
+ onTicketChange_: function() {
+ this.printButton_.disabled =
+ !this.printTicketStore_.isTicketValid() ||
+ !this.isEnabled_;
+ this.updateSummary_();
}
};
+ // Export
return {
PrintHeader: PrintHeader
};
diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css
index b484c2a..1c91d66 100644
--- a/chrome/browser/resources/print_preview/print_preview.css
+++ b/chrome/browser/resources/print_preview/print_preview.css
@@ -7,9 +7,9 @@ html {
}
body {
+ display: -webkit-box;
height: 100%;
margin: 0;
- overflow: hidden;
}
/* Header */
@@ -17,20 +17,16 @@ body {
header {
-webkit-padding-end: 14px;
-webkit-padding-start: 16px;
+ background-color: #F1F1F1;
}
#print-preview #navbar-container {
-webkit-border-end: 1px solid rgb(198, 201, 206);
-webkit-box-orient: vertical;
-webkit-user-select: none;
- background-color: #f1f1f1;
- bottom: 0;
+ background-color: white;
display: -webkit-box;
- /* We set both left and right for the sake of RTL. */
- left: 0;
- position: fixed;
- right: 0;
- top: 0;
+ position: relative;
width: 310px;
z-index: 2;
}
@@ -45,25 +41,14 @@ header {
text-shadow: white 0 1px 2px;
}
-#print-header {
- padding-bottom: 10px;
- padding-top: 10px;
-}
-
-#print-summary {
- color: rgb(83, 99, 125);
- display: block;
- min-height: 30px;
-}
-
/* Settings */
#settings {
- -webkit-box-flex: 1;
-webkit-box-shadow: inset 0 2px 2px rgba(0, 0, 0, .3);
background: white;
overflow-y: auto;
padding-top: 2px;
+ width: 100%;
}
.two-column {
@@ -87,10 +72,10 @@ header {
}
.two-column h1 {
+ -webkit-padding-end: 16px;
-webkit-padding-start: 16px;
display: table-cell;
font-size: 1.1em;
- width: 86px;
}
.two-column.visible h1,
@@ -117,19 +102,20 @@ h1 {
font-weight: 300;
}
-.preview-link-button {
- -webkit-padding-start: 16px;
+#print-preview .navbar-link {
+ -webkit-margin-start: 16px;
+ margin-top: 10px;
outline: 0;
- padding-top: 10px;
+ padding: 0;
text-align: start;
text-decoration: none;
}
-.preview-link-button:hover:not(:disabled) {
+#print-preview .navbar-link:hover:not(:disabled) {
text-decoration: underline;
}
-.preview-link-button:disabled {
+#print-preview .navbar-link:disabled {
color: rgba(0, 0, 0, .5);
cursor: default;
text-shadow: none;
@@ -241,150 +227,12 @@ label {
/* Individual settings sections */
-#print-pages-div {
- -webkit-box-align: center;
- -webkit-box-orient: horizontal;
- display: -webkit-box;
-}
-
-#individual-pages {
- -webkit-box-flex: 1;
- -webkit-margin-start: 5px;
- display: block;
-}
-
-#collate-option {
- -webkit-padding-start: 16px;
- display: inline-block;
-}
-
-#copies {
- position: relative;
- width: 2.75em;
-}
-
-#copies.invalid {
- background: rgb(255, 240, 240);
- color: rgb(140, 20, 20);
-}
-
-#increment,
-#decrement {
- -webkit-padding-end: 0;
- -webkit-padding-start: 0;
- font-weight: 600;
- margin: 0;
- min-width: 0;
- position: relative;
- width: 2em;
-}
-
-#increment:focus,
-#decrement:focus,
-#copies:focus {
- z-index: 1;
-}
-
-#increment {
- -webkit-margin-start: -5px;
- border-radius: 0;
-}
-
-#decrement {
- -webkit-margin-start: -5px;
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 3px;
- border-top-left-radius: 0;
- border-top-right-radius: 3px;
-}
-
-html[dir='rtl'] #decrement {
- border-bottom-left-radius: 3px;
- border-bottom-right-radius: 0;
- border-top-left-radius: 3px;
- border-top-right-radius: 0;
-}
-
-#system-dialog-link {
- -webkit-margin-start: 16px;
- margin-top: 10px;
- padding: 0;
-}
-
-/* PDF view */
-
-#mainview {
- -webkit-margin-start: 310px;
- -webkit-padding-start: 0;
- -webkit-user-select: none;
- background-color: #ccc;
- bottom: 0;
- left: 0;
- overflow: hidden;
- position: absolute;
- right: 0;
- top: 0;
- z-index: 1;
-}
-
-#pdf-viewer {
- /* pluginFadeInTransitionDuration = 200ms */
- -webkit-transition: opacity 200ms linear;
- /* pluginFadeInTransitionDelay = overlayFadeOutTransitionDuration = 100ms */
- -webkit-transition-delay: 100ms;
- height: 100%;
- opacity: 1;
- width: 100%;
-}
-
-#pdf-viewer.invisible {
- /* pluginFadeOutTransitionDuration = 100ms */
- -webkit-transition: opacity 100ms linear;
- /* pluginFadeOutTransitionDelay = 250ms */
- -webkit-transition-delay: 250ms;
- opacity: 0;
-}
-
-#no-plugin {
- padding: 20px;
-}
-
/* TODO(estade): this should be in a shared location but I'm afraid of the
* damage it could do. */
[hidden] {
display: none !important;
}
-#overlay-layer {
- -webkit-transition: opacity 200ms linear;
- /* overlayFadeInTransitionDelay = pluginFadeOutTransitionDelay +
- * pluginFadeOutTransitionDuration = 350ms */
- -webkit-transition-delay: 350ms;
- -webkit-user-select: none;
- background: #ccc;
- height: 100%;
- margin: 0;
- opacity: 1;
- position: absolute;
- width: 100%;
-}
-
-#overlay-layer.invisible {
- /* overlayFadeOutTransitionDuration = 100ms */
- -webkit-transition: opacity 100ms linear;
- opacity: 0;
- pointer-events: none;
-}
-
-#messages {
- color: #404040;
- font-size: 1.1em;
- position: relative;
- text-align: center;
- text-shadow: 0 1px 0 rgba(255, 255, 255, .5);
- top: 50%;
-}
-
@-webkit-keyframes dancing-dots-jump {
0% { top: 0; }
55% { top: 0; }
@@ -395,28 +243,20 @@ html[dir='rtl'] #decrement {
100% { top: 0; }
}
-#loading {
- -webkit-margin-end: -3px;
-}
-
-.message-with-dots span span {
+span.jumping-dots > span {
-webkit-animation: dancing-dots-jump 1800ms infinite;
padding: 1px;
position: relative;
}
-.message-with-dots span span:nth-child(2) {
+span.jumping-dots > span:nth-child(2) {
-webkit-animation-delay: 100ms;
}
-.message-with-dots span span:nth-child(3) {
+span.jumping-dots > span:nth-child(3) {
-webkit-animation-delay: 300ms;
}
-#error-action-area {
- margin-top: 10px;
-}
-
/* TODO(estade): unfork this code. */
.button-strip {
<if expr="not pp_ifdef('toolkit_views')">
@@ -431,3 +271,7 @@ html[dir='rtl'] #decrement {
-webkit-margin-start: 4px;
display: block;
}
+
+#link-container {
+ -webkit-box-flex: 1;
+}
diff --git a/chrome/browser/resources/print_preview/print_preview.html b/chrome/browser/resources/print_preview/print_preview.html
index 1090875..58bfce5 100644
--- a/chrome/browser/resources/print_preview/print_preview.html
+++ b/chrome/browser/resources/print_preview/print_preview.html
@@ -1,92 +1,77 @@
<!DOCTYPE html>
<html i18n-values="dir:textdirection;" id="print-preview">
+
<head>
-<meta charset="utf-8">
-<title i18n-content="title"></title>
-<link rel="icon" href="../../../app/theme/print_preview_favicon.png">
+ <meta charset="utf-8"/>
+ <title i18n-content="title"></title>
+ <link rel="icon" href="../../../app/theme/print_preview_favicon.png">
-<link rel="stylesheet" href="margins.css">
-<link rel="stylesheet" href="print_preview.css">
-<link rel="stylesheet" href="../shared/css/chrome_shared2.css">
-<link rel="stylesheet" href="../shared/css/throbber.css">
+ <link rel="stylesheet" href="print_preview.css"/>
+ <link rel="stylesheet" href="../shared/css/chrome_shared2.css"/>
+ <link rel="stylesheet" href="../shared/css/throbber.css"/>
+ <link rel="stylesheet" href="../shared/css/widgets.css"/>
+ <link rel="stylesheet" href="print_header.css"/>
+ <link rel="stylesheet" href="settings/copies_settings.css"/>
+ <link rel="stylesheet" href="settings/page_settings.css"/>
+ <link rel="stylesheet" href="previewarea/preview_area.css"/>
+ <link rel="stylesheet" href="previewarea/margin_control_container.css"/>
+ <link rel="stylesheet" href="previewarea/margin_control.css"/>
+ <link rel="stylesheet" href="../shared/css/overlay.css"/>
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/event_tracker.js"></script>
-<script src="chrome://resources/js/local_strings.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="chrome://print/print_preview.js"></script>
-<script src="chrome://print/strings.js"></script>
+ <script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/cr/event_target.js"></script>
+ <script src="chrome://resources/js/event_tracker.js"></script>
+ <script src="chrome://resources/js/local_strings.js"></script>
+ <script src="chrome://resources/js/util.js"></script>
+ <script src="chrome://print/print_preview.js"></script>
+ <script src="chrome://print/strings.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
</head>
+
<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
<div id="navbar-container">
<header>
<h1 id="navbar-content-title" i18n-content="title"></h1>
- <div id="print-header">
- <span id="print-summary"></span>
- <div class="button-strip">
- <button id="print-button" i18n-content="printButton" class="default">
- </button>
- <button id="cancel-button" i18n-content="cancelButton"></button>
- </div>
- </div>
+ <include src="print_header.html"/>
</header>
<div id="settings">
- <div id="destination-option" class="two-column visible">
- <h1 i18n-content="destinationLabel"></h1>
- <div class="right-column">
- <select id="printer-list"></select>
- </div>
- </div>
- <include src="page_settings.html"></include>
- <include src="copies_settings.html"></include>
- <include src="layout_settings.html"></include>
- <include src="color_settings.html"></include>
- <include src="margin_settings.html"></include>
- <include src="more_options.html"></include>
+ <include src="settings/destination_settings.html"/>
+ <include src="settings/page_settings.html"/>
+ <include src="settings/copies_settings.html"/>
+ <include src="settings/layout_settings.html"/>
+ <include src="settings/color_settings.html"/>
+ <include src="settings/margin_settings.html"/>
+ <include src="settings/other_options_settings.html"/>
+ </div>
+ <div id="link-container">
<div>
- <if expr="pp_ifdef('chromeos')">
- <button id="system-dialog-link"
- class="link-button preview-link-button"
- i18n-content="cloudPrintDialogOption"></button>
- </if>
- <if expr="not pp_ifdef('chromeos')">
- <button id="system-dialog-link"
- class="link-button preview-link-button"
- i18n-content="systemDialogOption"></button>
- </if>
- <div id="system-dialog-throbber" class="throbber" hidden></div>
+ <button id="cloud-print-dialog-link"
+ class="link-button navbar-link"
+ style="display: none;"
+ i18n-content="cloudPrintDialogOption"></button>
+ <button id="system-dialog-link"
+ class="link-button navbar-link"
+ style="display: none;"
+ i18n-content="systemDialogOption"></button>
+ <div id="dialog-throbber"
+ style="display: none;"
+ class="throbber"></div>
</div>
- <if expr="is_macosx">
- <div>
- <button id="open-pdf-in-preview-link"
- class="link-button preview-link-button"
- i18n-content="openPdfInPreviewOption"></button>
- <div id="open-preview-app-throbber" class="throbber" hidden></div>
- </div>
- </if>
- </div>
- </div>
- <div id="mainview">
- <div id="overlay-layer" class="invisible">
- <div id="messages">
- <div id="dancing-dots-text" hidden>
- <span id="loading"></span>
- <span><span>.</span><span>.</span><span>.</span></span>
- </div>
- <div id="custom-message" hidden></div>
- <div id="custom-message-with-dots"
- class="message-with-dots" hidden></div>
- <div id="error-action-area">
- <button id="error-button" hidden></button>
- <div id="native-print-dialog-throbber" class="throbber" hidden></div>
- </div>
+ <div>
+ <button id="open-pdf-in-preview-link"
+ class="link-button navbar-link"
+ style="display: none;"
+ i18n-content="openPdfInPreviewOption"></button>
+ <div id="open-preview-app-throbber"
+ style="display: none;"
+ class="throbber"></div>
</div>
</div>
</div>
- <object id="dummy-viewer"
- type="application/x-google-chrome-print-preview-pdf"
- data="chrome://print/dummy.pdf"></object>
- <script src="chrome://resources/js/i18n_template.js"></script>
- <script src="chrome://resources/js/i18n_process.js"></script>
+ <include src="previewarea/preview_area.html"/>
+
+ <!-- HTML Templates -->
+ <include src="previewarea/margin_control.html"/>
</body>
+
</html>
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index f47cb29..ed78cfc 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -2,1267 +2,916 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// require: cr/ui/print_preview_cloud.js
+// TODO(rltoscano): Might be a problem where might be in fetching destinations
+// state, then to file selection state, then cancel, which results in the
+// fetching destinations state being lost.
-var localStrings = new LocalStrings();
-
-// If useCloudPrint is true we attempt to connect to cloud print
-// and populate the list of printers with cloud print printers.
-var useCloudPrint = false;
-
-// Store the last selected printer index.
-var lastSelectedPrinterIndex = 0;
-
-// Used to disable some printing options when the preview is not modifiable.
-var previewModifiable = false;
-
-// Used to identify whether the printing frame has specific page size style.
-var hasPageSizeStyle = false;
-
-// Destination list special value constants.
-
-/** @const */ var MANAGE_CLOUD_PRINTERS = 'manageCloudPrinters';
-/** @const */ var MANAGE_LOCAL_PRINTERS = 'manageLocalPrinters';
-/** @const */ var SIGN_IN = 'signIn';
-/** @const */ var PRINT_TO_PDF = 'Save as PDF';
-/** @const */ var PRINT_WITH_CLOUD_PRINT = 'printWithCloudPrint';
-
-// State of the print preview settings.
-var printSettings = new PrintSettings();
-
-// Print ready data index.
-/** @const */ var PRINT_READY_DATA_INDEX = -1;
-
-// The name of the default or last used printer.
-var defaultOrLastUsedPrinterName = '';
-
-// True when a pending print preview request exists.
-var hasPendingPreviewRequest = false;
-
-// True when the first page is loaded in the plugin.
-var isFirstPageLoaded = false;
-
-// The ID of the last preview request.
-var lastPreviewRequestID = -1;
-
-// The ID of the initial preview request.
-var initialPreviewRequestID = -1;
-
-// True when a pending print file request exists.
-var hasPendingPrintDocumentRequest = false;
+// TODO(rltoscano): Move data/* into print_preview.data namespace
-// True when the complete metafile for the previewed doc is ready.
-var isPrintReadyMetafileReady = false;
+// TODO(rltoscano): Handle case where cloud print is initial destination, but
+// cloud print is not enabled.
-// True when preview tab is hidden.
-var isTabHidden = false;
-
-// True in kiosk mode where print preview can print automatically without
-// user intervention. See http://crbug.com/31395.
-var printAutomaticallyInKioskMode = false;
-
-// @type {print_preview.PrintHeader} Holds the print and cancel buttons.
-var printHeader;
-
-// @type {print_preview.PageSettings} Holds all the pages related settings.
-var pageSettings;
+var localStrings = new LocalStrings();
-// @type {print_preview.CopiesSettings} Holds all the copies related settings.
-var copiesSettings;
-
-// @type {print_preview.LayoutSettings} Holds all the layout related settings.
-var layoutSettings;
-
-// @type {print_preview.MarginSettings} Holds all the margin related settings.
-var marginSettings;
-
-// @type {print_preview.HeaderFooterSettings} Holds all the header footer
-// related settings.
-var headerFooterSettings;
-
-// @type {print_preview.FitToPageSettings} Holds all the fit to page related
-// settings.
-var fitToPageSettings;
-
-// @type {print_preview.MoreOptions} Holds the more options implementation.
-var moreOptions;
-
-// @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;
-
-// True if the user has clicked 'Open PDF in Preview' option.
-var previewAppRequested = false;
-
-// The range of options in the printer dropdown controlled by cloud print.
-var firstCloudPrintOptionPos = 0;
-var lastCloudPrintOptionPos = firstCloudPrintOptionPos;
-
-// Store the current previewUid.
-var currentPreviewUid = '';
-
-// True if we need to generate draft preview data.
-var generateDraftData = true;
-
-// The last element clicked with the mouse.
-var lastClickedElement = null;
-
-// A dictionary of cloud printers that have been added to the printer
-// dropdown.
-var addedCloudPrinters = {};
-
-// The maximum number of cloud printers to allow in the dropdown.
-/** @const */ var maxCloudPrinters = 10;
-
-/** @const */ var MIN_REQUEST_ID = 0;
-/** @const */ var MAX_REQUEST_ID = 32000;
-
-// Names of all the custom events used.
-var customEvents = {
- // Fired when the header footer option visibility changed.
- HEADER_FOOTER_VISIBILITY_CHANGED: 'headerFooterVisibilityChanged',
- // Fired when the mouse moves while a margin line is being dragged.
- MARGIN_LINE_DRAG: 'marginLineDrag',
- // Fired when a mousedown event occurs on a margin line.
- MARGIN_LINE_MOUSE_DOWN: 'marginLineMouseDown',
- // Fired when a margin textbox gains focus.
- MARGIN_TEXTBOX_FOCUSED: 'marginTextboxFocused',
- // Fired when a new preview might be needed because of margin changes.
- MARGINS_MAY_HAVE_CHANGED: 'marginsMayHaveChanged',
- // Fired when a pdf generation related error occurs.
- PDF_GENERATION_ERROR: 'PDFGenerationError',
- // Fired once the first page of the pdf document is loaded in the plugin.
- PDF_LOADED: 'PDFLoaded',
- // Fired when the selected printer capabilities change.
- PRINTER_CAPABILITIES_UPDATED: 'printerCapabilitiesUpdated',
- // Fired when the destination printer is changed.
- PRINTER_SELECTION_CHANGED: 'printerSelectionChanged',
- // Fired when the print button needs to be updated.
- UPDATE_PRINT_BUTTON: 'updatePrintButton',
- // Fired when the print summary needs to be updated.
- UPDATE_SUMMARY: 'updateSummary'
-};
-
-/**
- * Window onload handler, sets up the page and starts print preview by getting
- * the printer list.
- */
-function onLoad() {
- initialPreviewRequestID = randomInteger(MIN_REQUEST_ID, MAX_REQUEST_ID);
- lastPreviewRequestID = initialPreviewRequestID;
-
- previewArea = print_preview.PreviewArea.getInstance();
- printHeader = print_preview.PrintHeader.getInstance();
- document.addEventListener(customEvents.PDF_GENERATION_ERROR,
- cancelPendingPrintRequest);
- document.addEventListener('click', setLastClickedElement);
-
- if (!checkCompatiblePluginExists()) {
- disableInputElementsInSidebar();
- $('cancel-button').focus();
- previewArea.displayErrorMessageWithButtonAndNotify(
- localStrings.getString('noPlugin'),
- localStrings.getString('launchNativeDialog'),
- launchNativePrintDialog);
- $('mainview').parentElement.removeChild($('dummy-viewer'));
- return;
- }
-
- $('system-dialog-link').addEventListener('click', onSystemDialogLinkClicked);
- if (cr.isMac) {
- $('open-pdf-in-preview-link').addEventListener(
- 'click', onOpenPdfInPreviewLinkClicked);
- }
- $('mainview').parentElement.removeChild($('dummy-viewer'));
-
- $('printer-list').disabled = true;
-
- pageSettings = print_preview.PageSettings.getInstance();
- copiesSettings = print_preview.CopiesSettings.getInstance();
- layoutSettings = print_preview.LayoutSettings.getInstance();
- marginSettings = print_preview.MarginSettings.getInstance();
- headerFooterSettings = print_preview.HeaderFooterSettings.getInstance();
- fitToPageSettings = print_preview.FitToPageSettings.getInstance();
- moreOptions = print_preview.MoreOptions.getInstance();
- colorSettings = print_preview.ColorSettings.getInstance();
- $('printer-list').onchange = updateControlsWithSelectedPrinterCapabilities;
-
- previewArea.showLoadingAnimation();
- chrome.send('getInitialSettings');
-}
-
-/**
- * @param {object} initialSettings An object containing all the initial
- * settings.
- */
-function setInitialSettings(initialSettings) {
- setInitiatorTabTitle(initialSettings['initiatorTabTitle']);
- previewModifiable = initialSettings['previewModifiable'];
- if (previewModifiable) {
- print_preview.MarginSettings.setNumberFormatAndMeasurementSystem(
- initialSettings['numberFormat'],
- initialSettings['measurementSystem']);
- marginSettings.setLastUsedMargins(initialSettings);
- }
- printAutomaticallyInKioskMode =
- initialSettings['printAutomaticallyInKioskMode'];
- headerFooterSettings.setChecked(initialSettings['headerFooterEnabled']);
- copiesSettings.previousDuplexMode = initialSettings['duplex'];
- setDefaultPrinter(initialSettings['printerName'],
- initialSettings['cloudPrintData']);
-}
-
-/**
- * Disables the input elements in the sidebar.
- */
-function disableInputElementsInSidebar() {
- var els = $('navbar-container').querySelectorAll('input, button, select');
- for (var i = 0; i < els.length; i++) {
- if (els[i] == printHeader.cancelButton)
- continue;
- els[i].disabled = true;
- }
-}
-
-/**
- * Enables the input elements in the sidebar.
- */
-function enableInputElementsInSidebar() {
- var els = $('navbar-container').querySelectorAll('input, button, select');
- for (var i = 0; i < els.length; i++)
- els[i].disabled = false;
-}
-
-/**
- * Keep track of the last element to receive a click.
- * @param {Event} e The click event.
- */
-function setLastClickedElement(e) {
- lastClickedElement = e.target;
-}
-
-/**
- * Disables the controls in the sidebar, shows the throbber and instructs the
- * backend to open the native print dialog.
- */
-function onSystemDialogLinkClicked() {
- if (showingSystemDialog)
- return;
- showingSystemDialog = true;
- disableInputElementsInSidebar();
- printHeader.disableCancelButton();
- $('system-dialog-throbber').hidden = false;
- chrome.send('showSystemDialog');
-}
-
-/**
- * Disables the controls in the sidebar, shows the throbber and instructs the
- * backend to open the pdf in native preview app. This is only for Mac.
- */
-function onOpenPdfInPreviewLinkClicked() {
- if (previewAppRequested)
- return;
- previewAppRequested = true;
- disableInputElementsInSidebar();
- $('open-preview-app-throbber').hidden = false;
- printHeader.disableCancelButton();
- requestToPrintDocument();
-}
-
-/**
- * Similar to onSystemDialogLinkClicked(), but specific to the
- * 'Launch native print dialog' UI.
- */
-function launchNativePrintDialog() {
- if (showingSystemDialog)
- return;
- showingSystemDialog = true;
- previewArea.errorButton.disabled = true;
- printHeader.disableCancelButton();
- $('native-print-dialog-throbber').hidden = false;
- chrome.send('showSystemDialog');
-}
-
-/**
- * Notifies listeners of |customEvents.PRINTER_SELECTION_CHANGED| event about
- * the current selected printer.
- */
-function dispatchPrinterSelectionChangedEvent() {
- var customEvent = cr.Event(customEvents.PRINTER_SELECTION_CHANGED);
- customEvent.selectedPrinter = getSelectedPrinterName();
- document.dispatchEvent(customEvent);
-}
-
-/**
- * Gets the selected printer capabilities and updates the controls accordingly.
- */
-function updateControlsWithSelectedPrinterCapabilities() {
- var printerList = $('printer-list');
- var selectedIndex = printerList.selectedIndex;
- if (selectedIndex < 0)
- return;
- if (cr.isMac)
- $('open-pdf-in-preview-link').disabled = false;
-
- var skip_refresh = false;
- var selectedPrinterChanged = true;
- var selectedValue = printerList.options[selectedIndex].value;
- if (cloudprint.isCloudPrint(printerList.options[selectedIndex])) {
- cloudprint.updatePrinterCaps(printerList.options[selectedIndex],
- doUpdateCloudPrinterCapabilities);
- skip_refresh = true;
- } else if (selectedValue == SIGN_IN ||
- selectedValue == MANAGE_CLOUD_PRINTERS ||
- selectedValue == MANAGE_LOCAL_PRINTERS) {
- printerList.selectedIndex = lastSelectedPrinterIndex;
- chrome.send(selectedValue);
- skip_refresh = true;
- selectedPrinterChanged = false;
- } else if (selectedValue == PRINT_TO_PDF ||
- selectedValue == PRINT_WITH_CLOUD_PRINT) {
- updateWithPrinterCapabilities({
- 'disableColorOption': true,
- 'setColorAsDefault': true,
- 'setDuplexAsDefault': false,
- 'printerColorModelForColor': print_preview.ColorSettings.COLOR,
- 'printerDefaultDuplexValue': copiesSettings.UNKNOWN_DUPLEX_MODE,
- 'disableCopiesOption': true});
- if (cr.isChromeOS && selectedValue == PRINT_WITH_CLOUD_PRINT)
- requestToPrintDocument();
- } else {
- // This message will call back to 'updateWithPrinterCapabilities'
- // function.
- chrome.send('getPrinterCapabilities', [selectedValue]);
- }
- if (selectedPrinterChanged)
- dispatchPrinterSelectionChangedEvent();
-
- if (!skip_refresh) {
- lastSelectedPrinterIndex = selectedIndex;
-
- // Regenerate the preview data based on selected printer settings.
- // Do not reset the margins if no preview request has been made.
- var resetMargins = lastPreviewRequestID != initialPreviewRequestID;
- setDefaultValuesAndRegeneratePreview(resetMargins);
- }
-}
-
-/**
- * Helper function to do the actual work of updating cloud printer
- * capabilities.
- * @param {Object} printer The printer object to set capabilities for.
- */
-function doUpdateCloudPrinterCapabilities(printer) {
- var settings = {'disableColorOption': !cloudprint.supportsColor(printer),
- 'setColorAsDefault': cloudprint.colorIsDefault(printer),
- 'disableCopiesOption': true,
- 'disableLandscapeOption': true};
- updateWithPrinterCapabilities(settings);
- var printerList = $('printer-list');
- var selectedIndex = printerList.selectedIndex;
- lastSelectedPrinterIndex = selectedIndex;
-
- // Regenerate the preview data based on selected printer settings.
- // Do not reset the margins if no preview request has been made.
- var resetMargins = lastPreviewRequestID != initialPreviewRequestID;
- setDefaultValuesAndRegeneratePreview(resetMargins);
-}
-
-/**
- * Notifies listeners of |customEvents.PRINTER_CAPABILITIES_UPDATED| about the
- * capabilities of the currently selected printer. It is called from C++ too.
- * @param {Object} settingInfo printer setting information.
- */
-function updateWithPrinterCapabilities(settingInfo) {
- var customEvent = new cr.Event(customEvents.PRINTER_CAPABILITIES_UPDATED);
- customEvent.printerCapabilities = settingInfo;
- document.dispatchEvent(customEvent);
-}
-
-/**
- * Reloads the printer list.
- */
-function reloadPrintersList() {
- $('printer-list').length = 0;
- firstCloudPrintOptionPos = 0;
- lastCloudPrintOptionPos = 0;
- chrome.send('getPrinters');
-}
-
-/**
- * Turn on the integration of Cloud Print.
- * @param {string} cloudPrintURL The URL to use for cloud print servers.
- */
-function setUseCloudPrint(cloudPrintURL) {
- useCloudPrint = true;
- cloudprint.setBaseURL(cloudPrintURL);
-}
-
-/**
- * Take the PDF data handed to us and submit it to the cloud, closing the print
- * preview tab once the upload is successful.
- * @param {string} data Data to send as the print job.
- */
-function printToCloud(data) {
- cloudprint.printToCloud(data, finishedCloudPrinting);
-}
-
-/**
- * Cloud print upload of the PDF file is finished, time to close the dialog.
- */
-function finishedCloudPrinting() {
- closePrintPreviewTab();
-}
-
-/**
- * Updates the fit to page option state based on the print scaling option of
- * source pdf. PDF's have an option to enable/disable print scaling. When we
- * find out that the print scaling option is disabled for the source pdf, we
- * uncheck the fit to page checkbox. This function is called from C++ code.
- */
-function printScalingDisabledForSourcePDF() {
- fitToPageSettings.onPrintScalingDisabled();
-}
-
-/**
- * Checks whether the specified settings are valid.
- *
- * @return {boolean} true if settings are valid, false if not.
- */
-function areSettingsValid() {
- var selectedPrinter = getSelectedPrinterName();
- return pageSettings.isPageSelectionValid() &&
- marginSettings.areMarginSettingsValid() &&
- (copiesSettings.isValid() || selectedPrinter == PRINT_TO_PDF ||
- selectedPrinter == PRINT_WITH_CLOUD_PRINT);
-}
-
-/**
- * Creates an object based on the values in the printer settings.
- *
- * @return {Object} Object containing print job settings.
- */
-function getSettings() {
- var deviceName = getSelectedPrinterName();
- var printToPDF = deviceName == PRINT_TO_PDF;
- var printWithCloudPrint = deviceName == PRINT_WITH_CLOUD_PRINT;
-
- var settings =
- {'deviceName': deviceName,
- 'pageRange': pageSettings.selectedPageRanges,
- 'duplex': copiesSettings.duplexMode,
- 'copies': copiesSettings.numberOfCopies,
- 'collate': copiesSettings.isCollated(),
- 'landscape': layoutSettings.isLandscape(),
- 'color': colorSettings.colorMode,
- 'printToPDF': printToPDF,
- 'printWithCloudPrint': printWithCloudPrint,
- 'isFirstRequest' : false,
- 'headerFooterEnabled': headerFooterSettings.hasHeaderFooter(),
- 'marginsType': marginSettings.selectedMarginsValue,
- 'requestID': -1,
- 'generateDraftData': generateDraftData,
- 'fitToPageEnabled': fitToPageSettings.hasFitToPage(),
- 'previewModifiable': previewModifiable};
-
- if (marginSettings.isCustomMarginsSelected())
- settings['marginsCustom'] = marginSettings.customMargins;
-
- var printerList = $('printer-list');
- var selectedPrinter = printerList.selectedIndex;
- if (cloudprint.isCloudPrint(printerList.options[selectedPrinter])) {
- settings['cloudPrintID'] =
- printerList.options[selectedPrinter].value;
- }
- return settings;
-}
-
-/**
- * Creates an object based on the values in the printer settings.
- * Note: |lastPreviewRequestID| is being modified every time this function is
- * called. Only call this function when a preview request is actually sent,
- * otherwise (for example when debugging) call getSettings().
- *
- * @return {Object} Object containing print job settings.
- */
-function getSettingsWithRequestID() {
- var settings = getSettings();
- settings.requestID = generatePreviewRequestID();
- settings.isFirstRequest = isFirstPreviewRequest();
- return settings;
-}
-
-/**
- * @return {number} The next unused preview request id.
- */
-function generatePreviewRequestID() {
- return ++lastPreviewRequestID;
-}
-
-/**
- * @return {boolean} True iff a preview has been requested.
- */
-function hasRequestedPreview() {
- return lastPreviewRequestID != initialPreviewRequestID;
-}
-
-/**
- * @return {boolean} True if |lastPreviewRequestID| corresponds to the initial
- * preview request.
- */
-function isFirstPreviewRequest() {
- return lastPreviewRequestID == initialPreviewRequestID + 1;
-}
-
-/**
- * Checks if |previewResponseId| matches |lastPreviewRequestId|. Used to ignore
- * obsolete preview data responses.
- * @param {number} previewResponseId The id to check.
- * @return {boolean} True if previewResponseId reffers to the expected response.
- */
-function isExpectedPreviewResponse(previewResponseId) {
- return lastPreviewRequestID == previewResponseId;
-}
-
-/**
- * Returns the name of the selected printer or the empty string if no
- * printer is selected.
- * @return {string} The name of the currently selected printer.
- */
-function getSelectedPrinterName() {
- var printerList = $('printer-list');
- var selectedPrinter = printerList.selectedIndex;
- if (selectedPrinter < 0)
- return '';
- return printerList.options[selectedPrinter].value;
-}
-
-/**
- * Asks the browser to print the preview PDF based on current print
- * settings. If the preview is still loading, printPendingFile() will get
- * called once the preview loads.
- */
-function requestToPrintDocument() {
- hasPendingPrintDocumentRequest = !isPrintReadyMetafileReady;
- var selectedPrinterName = getSelectedPrinterName();
- var printToPDF = selectedPrinterName == PRINT_TO_PDF;
- var printWithCloudPrint = selectedPrinterName == PRINT_WITH_CLOUD_PRINT;
- if (hasPendingPrintDocumentRequest) {
- if (previewAppRequested) {
- previewArea.showCustomMessage(
+<include src="component.js"/>
+
+cr.define('print_preview', function() {
+ 'use strict';
+
+ /**
+ * Container class for Chromium's print preview.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function PrintPreview() {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to communicate with Chromium's print system.
+ * @type {!print_preview.NativeLayer}
+ * @private
+ */
+ this.nativeLayer_ = new print_preview.NativeLayer();
+
+ /**
+ * Data store which holds print destinations.
+ * @type {!print_preview.DestinationStore}
+ * @private
+ */
+ this.destinationStore_ = new print_preview.DestinationStore();
+
+ /**
+ * Storage of the print ticket used to create the print job.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = new print_preview.PrintTicketStore(
+ this.destinationStore_);
+
+ /**
+ * Holds the print and cancel buttons and renders some document statistics.
+ * @type {!print_preview.PrintHeader}
+ * @private
+ */
+ this.printHeader_ = new print_preview.PrintHeader(
+ this.printTicketStore_, this.destinationStore_);
+ this.addChild(this.printHeader_);
+
+ /**
+ * Component that renders the print destination.
+ * @type {!print_preview.DestinationSettings}
+ * @private
+ */
+ this.destinationSettings_ = new print_preview.DestinationSettings(
+ this.destinationStore_);
+ this.addChild(this.destinationSettings_);
+
+ /**
+ * Component that renders UI for entering in page range.
+ * @type {!print_preview.PageSettings}
+ * @private
+ */
+ this.pageSettings_ = new print_preview.PageSettings(this.printTicketStore_);
+ this.addChild(this.pageSettings_);
+
+ /**
+ * Component that renders the copies settings.
+ * @type {!print_preview.CopiesSettings}
+ * @private
+ */
+ this.copiesSettings_ = new print_preview.CopiesSettings(
+ this.printTicketStore_);
+ this.addChild(this.copiesSettings_);
+
+ /**
+ * Component that renders the layout settings.
+ * @type {!print_preview.LayoutSettings}
+ * @private
+ */
+ this.layoutSettings_ = new print_preview.LayoutSettings(
+ this.printTicketStore_);
+ this.addChild(this.layoutSettings_);
+
+ /**
+ * Component that renders the color options.
+ * @type {!print_preview.ColorSettings}
+ * @private
+ */
+ this.colorSettings_ = new print_preview.ColorSettings(
+ this.printTicketStore_);
+ this.addChild(this.colorSettings_);
+
+ /**
+ * Component that renders a select box for choosing margin settings.
+ * @type {!print_preview.MarginSettings}
+ * @private
+ */
+ this.marginSettings_ = new print_preview.MarginSettings(
+ this.printTicketStore_);
+ this.addChild(this.marginSettings_);
+
+ /**
+ * Component that renders miscellaneous print options.
+ * @type {!print_preview.OtherOptionsSettings}
+ * @private
+ */
+ this.otherOptionsSettings_ = new print_preview.OtherOptionsSettings(
+ this.printTicketStore_);
+ this.addChild(this.otherOptionsSettings_);
+
+ /**
+ * Area of the UI that holds the print preview.
+ * @type {!print_preview.PreviewArea}
+ * @private
+ */
+ this.previewArea_ = new print_preview.PreviewArea(
+ this.destinationStore_, this.printTicketStore_, this.nativeLayer_);
+ this.addChild(this.previewArea_);
+
+ /**
+ * Interface to the Google Cloud Print API. Null if Google Cloud Print
+ * integration is disabled.
+ * @type {cloudprint.CloudPrintInterface}
+ * @private
+ */
+ this.cloudPrintInterface_ = null;
+
+ /**
+ * Whether in kiosk mode where print preview can print automatically without
+ * user intervention. See http://crbug.com/31395. Print will start when
+ * both the print ticket has been initialized, and an initial printer has
+ * been selected.
+ * @type {boolean}
+ * @private
+ */
+ this.isInKioskAutoPrintMode_ = false;
+
+ /**
+ * State of the print preview UI.
+ * @type {print_preview.PrintPreview.UiState_}
+ * @private
+ */
+ this.uiState_ = PrintPreview.UiState_.INITIALIZING;
+
+ /**
+ * Current state of fetching destinations.
+ * @type {print_preview.PrintPreview.FetchState_}
+ * @private
+ */
+ this.fetchState_ = PrintPreview.FetchState_.READY;
+
+ /**
+ * Whether document preview generation is in progress.
+ * @type {boolean}
+ * @private
+ */
+ this.isPreviewGenerationInProgress_ = true;
+
+ this.tracker.add(window, 'DOMContentLoaded', this.onWindowLoad_.bind(this));
+ };
+
+ /**
+ * States of the print preview.
+ * @enum {string}
+ * @private
+ */
+ PrintPreview.UiState_ = {
+ INITIALIZING: 'initializing',
+ READY: 'ready',
+ OPENING_PDF_PREVIEW: 'opening-pdf-preview',
+ OPENING_NATIVE_PRINT_DIALOG: 'opening-native-print-dialog',
+ PRINTING: 'printing',
+ FILE_SELECTION: 'file-selection',
+ CLOSING: 'closing',
+ ERROR: 'error'
+ };
+
+ /**
+ * Bitfield of the states of fetching destinations.
+ * @enum {number}
+ * @private
+ */
+ PrintPreview.FetchState_ = {
+ READY: 1,
+ LOCAL_DESTINATIONS: 2,
+ RECENT_CLOUD_DESTINATIONS: 4,
+ ALL_CLOUD_DESTINATIONS: 8
+ };
+
+ PrintPreview.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ /** @override */
+ decorateInternal: function() {
+ this.printHeader_.decorate($('print-header'));
+ this.destinationSettings_.decorate($('destination-settings'));
+ this.pageSettings_.decorate($('page-settings'));
+ this.copiesSettings_.decorate($('copies-settings'));
+ this.layoutSettings_.decorate($('layout-settings'));
+ this.colorSettings_.decorate($('color-settings'));
+ this.marginSettings_.decorate($('margin-settings'));
+ this.otherOptionsSettings_.decorate($('other-options-settings'));
+ this.previewArea_.decorate($('preview-area'));
+
+ setIsVisible($('cloud-print-dialog-link'), cr.isChromeOS);
+ setIsVisible($('system-dialog-link'), !cr.isChromeOS);
+ setIsVisible($('open-pdf-in-preview-link'), cr.isMac);
+ },
+
+ /** @override */
+ enterDocument: function() {
+ // Native layer events.
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.INITIAL_SETTINGS_SET,
+ this.onInitialSettingsSet_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.CLOUD_PRINT_ENABLE,
+ this.onCloudPrintEnable_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.LOCAL_DESTINATIONS_SET,
+ this.onLocalDestinationsSet_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.CAPABILITIES_SET,
+ this.onLocalDestinationCapabilitiesSet_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.DESTINATIONS_RELOAD,
+ this.onDestinationsReload_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.PRINT_TO_CLOUD,
+ this.onPrintToCloud_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.FILE_SELECTION_CANCEL,
+ this.onFileSelectionCancel_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.FILE_SELECTION_COMPLETE,
+ this.onFileSelectionComplete_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.SETTINGS_INVALID,
+ this.onSettingsInvalid_.bind(this));
+ this.tracker.add(
+ this.nativeLayer_,
+ print_preview.NativeLayer.EventType.DISABLE_SCALING,
+ this.onDisableScaling_.bind(this));
+
+ this.tracker.add(
+ $('system-dialog-link'),
+ 'click',
+ this.openSystemPrintDialog_.bind(this));
+ this.tracker.add(
+ $('cloud-print-dialog-link'),
+ 'click',
+ this.openSystemPrintDialog_.bind(this));
+ this.tracker.add(
+ $('open-pdf-in-preview-link'),
+ 'click',
+ this.onOpenPdfInPreviewLinkClick_.bind(this));
+
+ this.tracker.add(
+ this.previewArea_,
+ print_preview.PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS,
+ this.onPreviewGenerationInProgress_.bind(this));
+ this.tracker.add(
+ this.previewArea_,
+ print_preview.PreviewArea.EventType.PREVIEW_GENERATION_DONE,
+ this.onPreviewGenerationDone_.bind(this));
+ this.tracker.add(
+ this.previewArea_,
+ print_preview.PreviewArea.EventType.PREVIEW_GENERATION_FAIL,
+ this.onPreviewGenerationFail_.bind(this));
+ this.tracker.add(
+ this.previewArea_,
+ print_preview.PreviewArea.EventType.OPEN_SYSTEM_DIALOG_CLICK,
+ this.openSystemPrintDialog_.bind(this));
+
+ this.tracker.add(
+ this.destinationStore_,
+ print_preview.DestinationStore.EventType.DESTINATION_SELECT,
+ this.onDestinationSelect_.bind(this));
+
+ this.tracker.add(
+ this.printHeader_,
+ print_preview.PrintHeader.EventType.PRINT_BUTTON_CLICK,
+ this.onPrintButtonClick_.bind(this));
+ this.tracker.add(
+ this.printHeader_,
+ print_preview.PrintHeader.EventType.CANCEL_BUTTON_CLICK,
+ this.onCancelButtonClick_.bind(this));
+
+ this.tracker.add(
+ this.destinationSettings_,
+ print_preview.DestinationSettings.EventType.MANAGE_PRINTERS_SELECT,
+ this.onManagePrinters_.bind(this));
+
+ this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this));
+ },
+
+ /**
+ * Sets whether the controls in the print preview are enabled.
+ * @param {boolean} isEnabled Whether the controls in the print preview are
+ * enabled.
+ * @private
+ */
+ setIsEnabled_: function(isEnabled) {
+ $('system-dialog-link').disabled = !isEnabled;
+ $('cloud-print-dialog-link').disabled = !isEnabled;
+ $('open-pdf-in-preview-link').disabled = !isEnabled;
+ this.printHeader_.isEnabled = isEnabled;
+ this.destinationSettings_.isEnabled = isEnabled;
+ this.pageSettings_.isEnabled = isEnabled;
+ this.copiesSettings_.isEnabled = isEnabled;
+ this.layoutSettings_.isEnabled = isEnabled;
+ this.colorSettings_.isEnabled = isEnabled;
+ this.marginSettings_.isEnabled = isEnabled;
+ this.otherOptionsSettings_.isEnabled = isEnabled;
+ },
+
+ /**
+ * Creates a local PDF print destination.
+ * @return {!print_preview.Destination} Created print destination.
+ * @private
+ */
+ createLocalPdfPrintDestination_: function() {
+ var dest = new print_preview.Destination(
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
+ localStrings.getString('printToPDF'),
+ false /*isRecent*/,
+ true /*isLocal*/);
+ dest.capabilities = new print_preview.ChromiumCapabilities(
+ false /*hasCopiesCapability*/,
+ '1' /*defaultCopiesStr*/,
+ false /*hasCollateCapability*/,
+ false /*defaultIsCollateEnabled*/,
+ false /*hasDuplexCapability*/,
+ false /*defaultIsDuplexEnabled*/,
+ true /*hasOrientationCapability*/,
+ false /*defaultIsLandscapeEnabled*/,
+ true /*hasColorCapability*/,
+ true /*defaultIsColorEnabled*/);
+ return dest;
+ },
+
+ /**
+ * Creates a new "Print with Cloud Print" print destination. NOTE: this
+ * destination will appear as "Search for additional printers..." on
+ * Chrome OS.
+ * @return {!print_preview.Destination} Created print destination.
+ * @private
+ */
+ createPrintWithCloudPrintDestination_: function() {
+ var dest = new print_preview.Destination(
+ print_preview.Destination.GooglePromotedId.PRINT_WITH_CLOUD_PRINT,
+ localStrings.getString('printWithCloudPrint'),
+ false /*isRecent*/,
+ false /*isLocal*/);
+ dest.capabilities = new print_preview.ChromiumCapabilities(
+ false /*hasCopiesCapability*/,
+ '1' /*defaultCopiesStr*/,
+ false /*hasCollateCapability*/,
+ false /*defaultIsCollateEnabled*/,
+ false /*hasDuplexCapability*/,
+ false /*defaultIsDuplexEnabled*/,
+ true /*hasOrientationCapability*/,
+ false /*defaultIsLandscapeEnabled*/,
+ true /*hasColorCapability*/,
+ true /*defaultIsColorEnabled*/);
+ return dest;
+ },
+
+ /**
+ * Prints the document or launches a pdf preview on the local system.
+ * @param {boolean} isPdfPreview Whether to launch the pdf preview.
+ * @private
+ */
+ printDocumentOrOpenPdfPreview_: function(isPdfPreview) {
+ assert(this.uiState_ == PrintPreview.UiState_.READY,
+ 'Print document request received when not in ready state: ' +
+ this.uiState_);
+ if (isPdfPreview) {
+ this.uiState_ = PrintPreview.UiState_.OPENING_PDF_PREVIEW;
+ } else if (this.destinationStore_.selectedDestination.id ==
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
+ this.uiState_ = PrintPreview.UiState_.FILE_SELECTION;
+ } else {
+ this.uiState_ = PrintPreview.UiState_.PRINTING;
+ }
+ this.setIsEnabled_(false);
+ if (this.printIfReady_() &&
+ ((this.destinationStore_.selectedDestination.isLocal &&
+ this.destinationStore_.selectedDestination.id !=
+ print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) ||
+ this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW)) {
+ // Hide the dialog for now. The actual print command will be issued when
+ // the preview generation is done.
+ this.nativeLayer_.startHideDialog();
+ }
+ },
+
+ /**
+ * Attempts to print if needed and if ready.
+ * @return {boolean} Whether a print request was issued.
+ * @private
+ */
+ printIfReady_: function() {
+ if ((this.uiState_ == PrintPreview.UiState_.PRINTING ||
+ this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW ||
+ this.uiState_ == PrintPreview.UiState_.FILE_SELECTION ||
+ this.isInKioskAutoPrintMode_) &&
+ !this.isPreviewGenerationInProgress_ &&
+ this.destinationStore_.selectedDestination &&
+ this.destinationStore_.selectedDestination.capabilities) {
+ assert(this.printTicketStore_.isTicketValid(),
+ 'Trying to print with invalid ticket');
+ this.nativeLayer_.startSaveDestinationAndTicket(
+ this.destinationStore_.selectedDestination,
+ this.printTicketStore_);
+ this.nativeLayer_.startPrint(
+ this.destinationStore_.selectedDestination,
+ this.printTicketStore_,
+ this.cloudPrintInterface_,
+ this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Closes the print preview.
+ * @private
+ */
+ close_: function() {
+ this.exitDocument();
+ this.uiState_ = PrintPreview.UiState_.CLOSING;
+ this.nativeLayer_.startCloseDialog();
+ },
+
+ /**
+ * Opens the native system print dialog after disabling all controls.
+ * @private
+ */
+ openSystemPrintDialog_: function() {
+ assert(this.uiState_ == PrintPreview.UiState_.READY,
+ 'Opening system dialog when not in ready state: ' + this.uiState_);
+ setIsVisible($('dialog-throbber'), true);
+ this.setIsEnabled_(false);
+ this.uiState_ = PrintPreview.UiState_.OPENING_NATIVE_PRINT_DIALOG;
+ this.nativeLayer_.startShowSystemDialog();
+ },
+
+ /**
+ * Window onload handler, sets up the page and starts print preview by
+ * getting the printer list.
+ * @private
+ */
+ onWindowLoad_: function() {
+ this.decorate($('print-preview'));
+ i18nTemplate.process(document, templateData);
+ if (!this.previewArea_.hasCompatiblePlugin) {
+ this.setIsEnabled_(false);
+ }
+ this.nativeLayer_.startGetInitialSettings();
+ this.nativeLayer_.startGetLocalDestinations();
+ },
+
+ /**
+ * Called when the native layer has initial settings to set. Sets the
+ * initial settings of the print preview and begins fetching print
+ * destinations.
+ * @param {cr.Event} event Contains the initial print preview settings
+ * persisted through the session.
+ * @private
+ */
+ onInitialSettingsSet_: function(event) {
+ assert(this.uiState_ == PrintPreview.UiState_.INITIALIZING,
+ 'Updating initial settings when not in initializing state: ' +
+ this.uiState_);
+ this.uiState_ = PrintPreview.UiState_.READY;
+
+ this.isInKioskAutoPrintMode_ =
+ event.initialSettings.isInKioskAutoPrintMode;
+ this.destinationStore_.setInitialDestinationId(
+ event.initialSettings.initialDestinationId);
+ this.printTicketStore_.initialize(
+ event.initialSettings.isDocumentModifiable,
+ event.initialSettings.isDuplexEnabled,
+ event.initialSettings.isHeaderFooterEnabled,
+ event.initialSettings.marginsType,
+ event.initialSettings.customMargins,
+ event.initialSettings.thousandsDelimeter,
+ event.initialSettings.decimalDelimeter,
+ event.initialSettings.unitType);
+ },
+
+ /**
+ * Calls when the native layer enables Google Cloud Print integration.
+ * Fetches the user's cloud printers.
+ * @param {cr.Event} event Contains the base URL of the Google Cloud Print
+ * service.
+ * @private
+ */
+ onCloudPrintEnable_: function(event) {
+ this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface(
+ event.baseCloudPrintUrl);
+ this.tracker.add(
+ this.cloudPrintInterface_,
+ cloudprint.CloudPrintInterface.EventType.SEARCH_DONE,
+ this.onCloudPrintSearchDone_.bind(this));
+ this.tracker.add(
+ this.cloudPrintInterface_,
+ cloudprint.CloudPrintInterface.EventType.PRINTER_DONE,
+ this.onCloudPrintPrinterDone_.bind(this));
+ this.tracker.add(
+ this.cloudPrintInterface_,
+ cloudprint.CloudPrintInterface.EventType.SUBMIT_DONE,
+ this.onCloudPrintSubmitDone_.bind(this));
+ this.tracker.add(
+ this.cloudPrintInterface_,
+ cloudprint.CloudPrintInterface.EventType.ERROR,
+ this.onCloudPrintError_.bind(this));
+
+ var printWithCloudPrintDest =
+ this.createPrintWithCloudPrintDestination_();
+ this.destinationStore_.insertDestination(printWithCloudPrintDest);
+
+ if (cr.isChromeOS) {
+ this.cloudPrintInterface_.search(true /*isRecent*/);
+ this.fetchState_ |= PrintPreview.FetchState_.RECENT_CLOUD_DESTINATIONS;
+ }
+ },
+
+ /**
+ * Called when the native layer gets local destinations. Adds local
+ * destination objects received from the operating system to the destination
+ * store. Also adds a save-as-pdf printer.
+ * @param {cr.Event} Contains the local destinations to set.
+ * @private
+ */
+ onLocalDestinationsSet_: function(event) {
+ var localDestinations = [];
+ for (var destInfo, i = 0; destInfo = event.destinationInfos[i]; i++) {
+ localDestinations.push(
+ print_preview.LocalDestinationParser.parse(destInfo));
+ }
+ localDestinations.push(this.createLocalPdfPrintDestination_());
+ this.destinationStore_.insertDestinations(localDestinations);
+ this.fetchState_ &= ~PrintPreview.FetchState_.LOCAL_DESTINATIONS;
+ },
+
+ /**
+ * Called when the native layer retrieves the capabilities for the selected
+ * local destination.
+ * @param {cr.Event} event Contains the capabilities of the local print
+ * destination.
+ * @private
+ */
+ onLocalDestinationCapabilitiesSet_: function(event) {
+ // TODO(rltoscano): There may be a race condition here. This method is
+ // assumed to return capabilities for the currently selected printer. But
+ // between the time the local printer was selected and the capabilities
+ // were retrieved, the selected printer can change. One way to address
+ // this is to include the destination ID in the settingsInfo parameter.
+ var selectedDestination = this.destinationStore_.selectedDestination;
+ if (selectedDestination.isLocal) {
+ var capabilities = print_preview.LocalCapabilitiesParser.parse(
+ event.settingsInfo);
+ selectedDestination.capabilities = capabilities;
+ this.printTicketStore_.updateDestinationCapabilities(capabilities);
+ this.printIfReady_();
+ }
+ },
+
+ /**
+ * Called from native layer after the user was requested to sign in, and did
+ * so successfully.
+ * @private
+ */
+ onDestinationsReload_: function() {
+ this.destinationStore_.clear();
+ this.nativeLayer_.startGetLocalDestinations();
+ if (this.cloudPrintInterface_) {
+ // Fetch recent printers.
+ this.cloudPrintInterface_.search(true /*isRecent*/);
+ // Fetch the full printer list.
+ this.cloudPrintInterface_.search(false /*isRecent*/);
+ }
+ this.fetchState_ =
+ PrintPreview.FetchState_.LOCAL_DESTINATIONS |
+ PrintPreview.FetchState_.ALL_CLOUD_DESTINATIONS |
+ PrintPreview.FetchState_.RECENT_CLOUD_DESTINATIONS;
+ },
+
+ /**
+ * Called from the native layer when ready to print to Google Cloud Print.
+ * @param {cr.Event} event Contains the body to send in the HTTP request.
+ * @private
+ */
+ onPrintToCloud_: function(event) {
+ assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
+ 'Document ready to be sent to the cloud when not in printing ' +
+ 'state: ' + this.uiState_);
+ assert(this.cloudPrintInterface_ != null,
+ 'Google Cloud Print is not enabled');
+ this.cloudPrintInterface_.submit(event.data);
+ },
+
+ /**
+ * Called from the native layer when the user cancels the save-to-pdf file
+ * selection dialog.
+ * @private
+ */
+ onFileSelectionCancel_: function() {
+ assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
+ 'File selection cancelled when not in file-selection state: ' +
+ this.uiState_);
+ this.setIsEnabled_(true);
+ this.uiState_ = PrintPreview.UiState_.READY;
+ },
+
+ /**
+ * Called from the native layer when save-to-pdf file selection is complete.
+ * @private
+ */
+ onFileSelectionComplete_: function() {
+ assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
+ 'File selection completed when not in file-selection state: ' +
+ this.uiState_);
+ this.previewArea_.showCustomMessage(
+ localStrings.getString('printingToPDFInProgress'));
+ this.uiState_ = PrintPreview.UiState_.PRINTING;
+ },
+
+ /**
+ * Called when the Google Cloud Print search API call completes. Adds
+ * destinations to the printer store and selects one if it matches the
+ * initial destination.
+ * @param {cr.Event} event Contains the new cloud destinations.
+ * @private
+ */
+ onCloudPrintSearchDone_: function(event) {
+ this.destinationStore_.insertDestinations(event.printers);
+ if (event.isRecent) {
+ this.fetchState_ &= ~PrintPreview.FetchState_.RECENT_CLOUD_DESTINATIONS;
+ } else {
+ this.fetchState_ &= ~PrintPreview.FetchState_.ALL_CLOUD_DESTINATIONS;
+ }
+ },
+
+ /**
+ * Called when the Google Cloud Print printer API call completes. Updates
+ * the UI with the newly received capabilities.
+ * @param {cr.Event} event Contains the destination returned in the printer
+ * API call.
+ */
+ onCloudPrintPrinterDone_: function(event) {
+ var dest = this.destinationStore_.updateDestination(event.printer);
+ if (this.destinationStore_.selectedDestination == dest) {
+ this.printTicketStore_.updateDestinationCapabilities(dest.capabilities);
+ this.printIfReady_();
+ }
+ },
+
+ /**
+ * Called after successfully submitting a job to Google Cloud Print.
+ * @private
+ */
+ onCloudPrintSubmitDone_: function() {
+ assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
+ 'Submited job to Google Cloud Print but not in printing state ' +
+ this.uiState_);
+ this.close_();
+ },
+
+ /**
+ * Called when there was an error communicating with Google Cloud print.
+ * Displays an error message in the print header.
+ * @param {cr.Event} event Contains the error message.
+ * @private
+ */
+ onCloudPrintError_: function(event) {
+ if (cr.isChromeOS && event.message == '403') {
+ this.nativeLayer_.startCloudPrintSignIn();
+ } else {
+ this.printHeader_.setErrorMessage(event.message);
+ }
+ this.fetchState_ &=
+ ~PrintPreview.FetchState_.RECENT_CLOUD_DESTINATIONS &
+ ~PrintPreview.FetchState_.ALL_CLOUD_DESTINATIONS;
+ },
+
+ /**
+ * Called when a new destination has been selected. Fetches the
+ * destination's capability list.
+ * @private
+ */
+ onDestinationSelect_: function() {
+ var destination = this.destinationStore_.selectedDestination;
+
+ // Fetch destination capabilities if necessary.
+ if (!destination.capabilities) {
+ if (destination.isLocal) {
+ this.nativeLayer_.startGetLocalDestinationCapabilities(
+ destination.id);
+ } else {
+ assert(this.cloudPrintInterface_ != null,
+ 'Selected destination is a cloud destination, but Google ' +
+ 'Cloud Print is not enabled');
+ this.cloudPrintInterface_.printer(destination.id);
+ }
+ } else {
+ this.printTicketStore_.updateDestinationCapabilities(
+ destination.capabilities);
+ }
+
+ this.printIfReady_();
+ },
+
+ /**
+ * Called when the preview area's preview generation is in progress.
+ * @private
+ */
+ onPreviewGenerationInProgress_: function() {
+ this.isPreviewGenerationInProgress_ = true;
+ },
+
+ /**
+ * Called when the preview area's preview generation is complete.
+ * @private
+ */
+ onPreviewGenerationDone_: function() {
+ this.isPreviewGenerationInProgress_ = false;
+ this.printIfReady_();
+ },
+
+ /**
+ * Called when the preview area's preview failed to load.
+ * @private
+ */
+ onPreviewGenerationFail_: function() {
+ this.isPreviewGenerationInProgress_ = false;
+ if (this.uiState_ == PrintPreview.UiState_.PRINTING) {
+ this.nativeLayer_.startCancelPendingPrint();
+ }
+ },
+
+ /**
+ * Called when the 'Open pdf in preview' link is clicked. Launches the pdf
+ * preview app.
+ * @private
+ */
+ onOpenPdfInPreviewLinkClick_: function() {
+ assert(this.uiState_ == PrintPreview.UiState_.READY,
+ 'Trying to open pdf in preview when not in ready state: ' +
+ this.uiState_);
+ setIsVisible($('open-preview-app-throbber'), true);
+ this.previewArea_.showCustomMessage(
localStrings.getString('openingPDFInPreview'));
- } else if (printToPDF) {
- sendPrintDocumentRequest();
- } else if (printWithCloudPrint) {
- previewArea.showCustomMessage(
- localStrings.getString('printWithCloudPrintWait'));
- disableInputElementsInSidebar();
- } else {
- isTabHidden = true;
- chrome.send('hidePreview');
- }
- return;
- }
-
- if (printToPDF || previewAppRequested) {
- sendPrintDocumentRequest();
- } else {
- window.setTimeout(function() { sendPrintDocumentRequest(); }, 1000);
- }
-}
-
-/**
- * Sends a message to cancel the pending print request.
- */
-function cancelPendingPrintRequest() {
- if (isTabHidden)
- chrome.send('cancelPendingPrintRequest');
-}
-
-/**
- * Sends a message to initiate print workflow.
- */
-function sendPrintDocumentRequest() {
- var printerList = $('printer-list');
- var printer = printerList[printerList.selectedIndex];
- chrome.send('saveLastPrinter', [printer.value, cloudprint.getData(printer)]);
-
- var settings = getSettings();
- if (cr.isMac && previewAppRequested)
- settings.OpenPDFInPreview = true;
-
- chrome.send('print', [JSON.stringify(settings),
- cloudprint.getPrintTicketJSON(printer)]);
-}
-
-/**
- * Loads the selected preview pages.
- */
-function loadSelectedPages() {
- pageSettings.updatePageSelection();
- var pageSet = pageSettings.previouslySelectedPages;
- var pageCount = pageSet.length;
- if (pageCount == 0 || currentPreviewUid == '')
- return;
-
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
- for (var i = 0; i < pageCount; i++)
- onDidPreviewPage(pageSet[i] - 1, currentPreviewUid, lastPreviewRequestID);
-}
-
-/**
- * Updates the variables states for preview.
- */
-function updateStateForPreview() {
- if (!isTabHidden)
- previewArea.showLoadingAnimation();
-
- if (!hasPendingPreviewRequest && previewModifiable &&
- hasOnlyPageSettingsChanged()) {
- loadSelectedPages();
- generateDraftData = false;
- } else {
- hasPendingPreviewRequest = true;
- generateDraftData = true;
- pageSettings.updatePageSelection();
- }
-
- printSettings.save();
- layoutSettings.updateState();
- previewArea.resetState();
- isPrintReadyMetafileReady = false;
- isFirstPageLoaded = false;
-
- var totalPageCount = pageSettings.totalPageCount;
- if (!previewModifiable && totalPageCount > 0)
- generateDraftData = false;
-}
-
-/**
- * Asks the browser to generate a preview PDF based on current print settings.
- */
-function requestPrintPreview() {
- updateStateForPreview();
- var totalPageCount = pageSettings.totalPageCount;
- var pageCount = totalPageCount || -1;
- chrome.send('getPreview', [JSON.stringify(getSettingsWithRequestID()),
- pageCount,
- previewModifiable]);
-}
-
-/**
- * Called from PrintPreviewUI::OnFileSelectionCancelled to notify the print
- * preview tab regarding the file selection cancel event.
- */
-function fileSelectionCancelled() {
- printHeader.enableCancelButton();
-}
-
-/**
- * Called from PrintPreviewUI::OnFileSelectionCompleted to notify the print
- * preview tab regarding the file selection completed event.
- */
-function fileSelectionCompleted() {
- // If the file selection is completed and the tab is not already closed it
- // means that a pending print to pdf request exists.
- disableInputElementsInSidebar();
- previewArea.showCustomMessage(
- localStrings.getString('printingToPDFInProgress'));
-}
-
-/**
- * Set the default printer. If there is one, generate a print preview.
- * @param {string} printerName Name of the default printer. Empty if none.
- * @param {string} cloudPrintData Cloud print related data to restore if
- * the default printer is a cloud printer.
- */
-function setDefaultPrinter(printerName, cloudPrintData) {
- // Add a placeholder value so the printer list looks valid.
- addDestinationListOption('', '', true, true, true);
- if (printerName) {
- defaultOrLastUsedPrinterName = printerName;
- if (cloudPrintData) {
- cloudprint.setDefaultPrinter(printerName,
- cloudPrintData,
- addDestinationListOptionAtPosition,
- doUpdateCloudPrinterCapabilities);
- } else {
- $('printer-list')[0].value = defaultOrLastUsedPrinterName;
- updateControlsWithSelectedPrinterCapabilities();
- }
- }
- chrome.send('getPrinters');
-}
-
-/**
- * Fill the printer list drop down.
- * Called from PrintPreviewHandler::SetupPrinterList().
- * @param {Array} printers Array of printer info objects.
- */
-function setPrinters(printers) {
- var printerList = $('printer-list');
- // Remove empty entry added by setDefaultPrinter.
- if (printerList[0] && printerList[0].textContent == '')
- printerList.remove(0);
- for (var i = 0; i < printers.length; ++i) {
- var isDefault = (printers[i].deviceName == defaultOrLastUsedPrinterName);
- addDestinationListOption(printers[i].printerName, printers[i].deviceName,
- isDefault, false, false);
- }
-
- if (printers.length != 0)
- addDestinationListOption('', '', false, true, true);
-
- // Adding option for saving PDF to disk.
- addDestinationListOption(localStrings.getString('printToPDF'),
- PRINT_TO_PDF,
- defaultOrLastUsedPrinterName == PRINT_TO_PDF,
- false,
- false);
- addDestinationListOption('', '', false, true, true);
- if (useCloudPrint) {
- addDestinationListOption(localStrings.getString('printWithCloudPrint'),
- PRINT_WITH_CLOUD_PRINT,
- false,
- false,
- false);
- addDestinationListOption('', '', false, true, true);
- }
- // Add options to manage printers.
- if (!cr.isChromeOS) {
- addDestinationListOption(localStrings.getString('managePrinters'),
- MANAGE_LOCAL_PRINTERS, false, false, false);
- } else if (useCloudPrint) {
- // Fetch recent printers.
- cloudprint.fetchPrinters(addDestinationListOptionAtPosition, false);
- // Fetch the full printer list.
- cloudprint.fetchPrinters(addDestinationListOptionAtPosition, true);
- addDestinationListOption(localStrings.getString('managePrinters'),
- MANAGE_CLOUD_PRINTERS, false, false, false);
- }
-
- printerList.disabled = false;
-
- if (!hasRequestedPreview())
- updateControlsWithSelectedPrinterCapabilities();
-}
-
-/**
- * Creates an option that can be added to the printer destination list.
- * @param {string} optionText specifies the option text content.
- * @param {string} optionValue specifies the option value.
- * @param {boolean} isDefault is true if the option needs to be selected.
- * @param {boolean} isDisabled is true if the option needs to be disabled.
- * @param {boolean} isSeparator is true if the option is a visual separator and
- * needs to be disabled.
- * @return {Object} The created option.
- */
-function createDestinationListOption(optionText, optionValue, isDefault,
- isDisabled, isSeparator) {
- var option = document.createElement('option');
- option.textContent = optionText;
- option.value = optionValue;
- option.selected = isDefault;
- option.disabled = isSeparator || isDisabled;
- // Adding attribute for improved accessibility.
- if (isSeparator)
- option.setAttribute('role', 'separator');
- return option;
-}
-
-/**
- * Adds an option to the printer destination list.
- * @param {string} optionText specifies the option text content.
- * @param {string} optionValue specifies the option value.
- * @param {boolean} isDefault is true if the option needs to be selected.
- * @param {boolean} isDisabled is true if the option needs to be disabled.
- * @param {boolean} isSeparator is true if the option serves just as a
- * separator.
- * @return {Object} The created option.
- */
-function addDestinationListOption(optionText, optionValue, isDefault,
- isDisabled, isSeparator) {
- var option = createDestinationListOption(optionText,
- optionValue,
- isDefault,
- isDisabled,
- isSeparator);
- $('printer-list').add(option);
- return option;
-}
-
-/**
- * Adds an option to the printer destination list at a specified position.
- * @param {number} position The index in the printer-list wher the option
- should be created.
- * @param {string} optionText specifies the option text content.
- * @param {string} optionValue specifies the option value.
- * @param {boolean} isDefault is true if the option needs to be selected.
- * @param {boolean} isDisabled is true if the option needs to be disabled.
- * @param {boolean} isSeparator is true if the option is a visual separator and
- * needs to be disabled.
- * @return {Object} The created option.
- */
-function addDestinationListOptionAtPosition(position,
- optionText,
- optionValue,
- isDefault,
- isDisabled,
- isSeparator) {
- var option = createDestinationListOption(optionText,
- optionValue,
- isDefault,
- isDisabled,
- isSeparator);
- var printerList = $('printer-list');
- var before = printerList[position];
- printerList.add(option, before);
- return option;
-}
-/**
- * Sets the color mode for the PDF plugin.
- * Called from PrintPreviewHandler::ProcessColorSetting().
- * @param {boolean} color is true if the PDF plugin should display in color.
- */
-function setColor(color) {
- if (!previewArea.pdfPlugin)
- return;
-
- previewArea.pdfPlugin.grayscale(!color);
- var printerList = $('printer-list');
- cloudprint.setColor(printerList[printerList.selectedIndex], color);
-}
-
-/**
- * Display an error message when print preview fails.
- * Called from PrintPreviewMessageHandler::OnPrintPreviewFailed().
- */
-function printPreviewFailed() {
- previewArea.displayErrorMessageAndNotify(
- localStrings.getString('previewFailed'));
-}
-
-/**
- * Display an error message when encountered invalid printer settings.
- * Called from PrintPreviewMessageHandler::OnInvalidPrinterSettings().
- */
-function invalidPrinterSettings() {
- if (cr.isMac) {
- if (previewAppRequested) {
- $('open-preview-app-throbber').hidden = true;
- previewArea.clearCustomMessageWithDots();
- previewAppRequested = false;
- hasPendingPrintDocumentRequest = false;
- enableInputElementsInSidebar();
- }
- $('open-pdf-in-preview-link').disabled = true;
- }
- previewArea.displayErrorMessageAndNotify(
- localStrings.getString('invalidPrinterSettings'));
-}
-
-/**
- * Called when the PDF plugin loads its document.
- */
-function onPDFLoad() {
- if (previewModifiable) {
- setPluginPreviewPageCount();
- } else {
- // If the source is pdf, print ready metafile is available only after
- // loading the pdf in the plugin.
- isPrintReadyMetafileReady = true;
- }
- // Instruct the plugin which page numbers to display in the page number
- // indicator.
- previewArea.pdfPlugin.setPageNumbers(
- JSON.stringify(pageSettings.selectedPagesSet));
- cr.dispatchSimpleEvent(document, customEvents.PDF_LOADED);
- isFirstPageLoaded = true;
- checkAndHideOverlayLayerIfValid();
- sendPrintDocumentRequestIfNeeded();
- if (printAutomaticallyInKioskMode)
- printHeader.printButton.click();
-}
-
-function setPluginPreviewPageCount() {
- previewArea.pdfPlugin.printPreviewPageCount(
- pageSettings.previouslySelectedPages.length);
-}
-
-/**
- * Update the page count and check the page range.
- * Called from PrintPreviewUI::OnDidGetPreviewPageCount().
- * @param {number} pageCount The number of pages.
- * @param {number} previewResponseId The preview request id that resulted in
- * this response.
- */
-function onDidGetPreviewPageCount(pageCount, previewResponseId) {
- if (!isExpectedPreviewResponse(previewResponseId))
- return;
- pageSettings.updateState(pageCount);
- if (!previewModifiable && pageSettings.requestPrintPreviewIfNeeded())
- return;
-
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY);
-}
-
-/**
- * @param {{contentWidth: number, contentHeight: number, marginLeft: number,
- * marginRight: number, marginTop: number, marginBottom: number,
- * printableAreaX: number, printableAreaY: number,
- * printableAreaWidth: number, printableAreaHeight: number}} pageLayout
- * Specifies default page layout details in points.
- * @param {boolean} hasCustomPageSizeStyle Indicates whether the previewed
- * document has a custom page size style.
- */
-function onDidGetDefaultPageLayout(pageLayout, hasCustomPageSizeStyle) {
- hasPageSizeStyle = hasCustomPageSizeStyle;
- marginSettings.currentDefaultPageLayout = new print_preview.PageLayout(
- pageLayout.contentWidth,
- pageLayout.contentHeight,
- pageLayout.marginLeft,
- pageLayout.marginTop,
- pageLayout.marginRight,
- pageLayout.marginBottom);
- headerFooterSettings.checkAndHideHeaderFooterOption(
- pageLayout, marginSettings.selectedMarginsValue);
-}
-
-/**
- * This function sends a request to hide the overlay layer only if there is no
- * pending print document request and we are not waiting for the print ready
- * metafile.
- */
-function checkAndHideOverlayLayerIfValid() {
- var selectedPrinter = getSelectedPrinterName();
- var printToDialog = selectedPrinter == PRINT_TO_PDF ||
- selectedPrinter == PRINT_WITH_CLOUD_PRINT;
- if ((printToDialog || !previewModifiable) &&
- !isPrintReadyMetafileReady && hasPendingPrintDocumentRequest) {
- return;
- }
- previewArea.hideOverlayLayer();
-}
-
-/**
- * Called when no pipelining previewed pages.
- * @param {string} previewUid Preview unique identifier.
- * @param {number} previewResponseId The preview request id that resulted in
- * this response.
- */
-function reloadPreviewPages(previewUid, previewResponseId) {
- if (!isExpectedPreviewResponse(previewResponseId))
- return;
-
- if (!previewModifiable)
- previewArea.createOrReloadPDFPlugin(PRINT_READY_DATA_INDEX);
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- checkAndHideOverlayLayerIfValid();
- var pageSet = pageSettings.previouslySelectedPages;
- for (var i = 0; i < pageSet.length; i++) {
- previewArea.pdfPlugin.loadPreviewPage(
- getPageSrcURL(previewUid, pageSet[i] - 1), i);
- }
-
- hasPendingPreviewRequest = false;
- isPrintReadyMetafileReady = true;
- previewArea.pdfLoaded = true;
- sendPrintDocumentRequestIfNeeded();
-}
-
-/**
- * Notification that a print preview page has been rendered.
- * Check if the settings have changed and request a regeneration if needed.
- * Called from PrintPreviewUI::OnDidPreviewPage().
- * @param {number} pageNumber The page number, 0-based.
- * @param {string} previewUid Preview unique identifier.
- * @param {number} previewResponseId The preview request id that resulted in
- * this response.
- */
-function onDidPreviewPage(pageNumber, previewUid, previewResponseId) {
- if (!isExpectedPreviewResponse(previewResponseId))
- return;
-
- // Refactor
- if (!previewModifiable)
- return;
-
- if (pageSettings.requestPrintPreviewIfNeeded())
- return;
-
- var pageIndex = pageSettings.previouslySelectedPages.indexOf(pageNumber + 1);
- if (pageIndex == -1)
- return;
-
- currentPreviewUid = previewUid;
- if (pageIndex == 0)
- previewArea.createOrReloadPDFPlugin(pageNumber);
-
- previewArea.pdfPlugin.loadPreviewPage(
- getPageSrcURL(previewUid, pageNumber), pageIndex);
-
- if (pageIndex + 1 == pageSettings.previouslySelectedPages.length) {
- hasPendingPreviewRequest = false;
- if (pageIndex != 0)
- sendPrintDocumentRequestIfNeeded();
- }
-}
-
-/**
- * Update the print preview when new preview data is available.
- * Create the PDF plugin as needed.
- * Called from PrintPreviewUI::PreviewDataIsAvailable().
- * @param {string} previewUid Preview unique identifier.
- * @param {number} previewResponseId The preview request id that resulted in
- * this response.
- */
-function updatePrintPreview(previewUid, previewResponseId) {
- if (!isExpectedPreviewResponse(previewResponseId))
- return;
-
- if (!previewModifiable) {
- // If the preview is not modifiable the plugin has not been created yet.
- currentPreviewUid = previewUid;
- hasPendingPreviewRequest = false;
- previewArea.createOrReloadPDFPlugin(PRINT_READY_DATA_INDEX);
- } else {
- isPrintReadyMetafileReady = true;
- }
-
- cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON);
- if (previewModifiable)
- sendPrintDocumentRequestIfNeeded();
-}
-
-/**
- * Checks to see if the requested print data is available for printing and
- * sends a print document request if needed.
- */
-function sendPrintDocumentRequestIfNeeded() {
- if (!hasPendingPrintDocumentRequest || !isFirstPageLoaded)
- return;
-
- // If the selected printer is PRINT_TO_PDF or PRINT_WITH_CLOUD_PRINT or
- // the preview source is not modifiable, we need the print ready data for
- // printing. If the preview source is modifiable, we need to wait till all
- // the requested pages are loaded in the plugin for printing.
- var selectedPrinter = getSelectedPrinterName();
- var printToDialog = selectedPrinter == PRINT_TO_PDF ||
- selectedPrinter == PRINT_WITH_CLOUD_PRINT;
- if (((printToDialog || !previewModifiable) && !isPrintReadyMetafileReady) ||
- (previewModifiable && hasPendingPreviewRequest)) {
- return;
- }
-
- hasPendingPrintDocumentRequest = false;
-
- if (!areSettingsValid()) {
- cancelPendingPrintRequest();
- return;
- }
- sendPrintDocumentRequest();
-}
-
-/**
- * Check if only page selection has been changed since the last preview request
- * and is valid.
- * @return {boolean} true if the new page selection is valid.
- */
-function hasOnlyPageSettingsChanged() {
- var tempPrintSettings = new PrintSettings();
- tempPrintSettings.save();
-
- return !!(printSettings.deviceName == tempPrintSettings.deviceName &&
- printSettings.isLandscape == tempPrintSettings.isLandscape &&
- printSettings.hasHeaderFooter ==
- tempPrintSettings.hasHeaderFooter &&
- pageSettings.hasPageSelectionChangedAndIsValid());
-}
-
-/**
- * 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');
- 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.setPageNumbers,
- 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;
-}
-
-/**
- * Sets the default values and sends a request to regenerate preview data.
- * Resets the margin options only if |resetMargins| is true.
- * @param {boolean} resetMargins True if margin settings should be resetted.
- */
-function setDefaultValuesAndRegeneratePreview(resetMargins) {
- if (resetMargins)
- marginSettings.resetMarginsIfNeeded();
- pageSettings.resetState();
- requestPrintPreview();
-}
-
-/**
- * Class that represents the state of the print settings.
- * @constructor
- */
-function PrintSettings() {
- this.deviceName = '';
- this.isLandscape = '';
- this.hasHeaderFooter = '';
-}
-
-/**
- * Takes a snapshot of the print settings.
- */
-PrintSettings.prototype.save = function() {
- this.deviceName = getSelectedPrinterName();
- this.isLandscape = layoutSettings.isLandscape();
- this.hasHeaderFooter = headerFooterSettings.hasHeaderFooter();
-};
-
-/**
- * Updates the title of the print preview tab according to |initiatorTabTitle|.
- * @param {string} initiatorTabTitle The title of the initiator tab.
- */
-function setInitiatorTabTitle(initiatorTabTitle) {
- if (initiatorTabTitle == '')
- return;
- document.title = localStrings.getStringF(
- 'printPreviewTitleFormat', initiatorTabTitle);
-}
-
-/**
- * Closes this print preview tab.
- */
-function closePrintPreviewTab() {
- window.removeEventListener('keydown', onKeyDown);
- chrome.send('closePrintPreviewTab');
- chrome.send('DialogClose');
-}
-
-/**
- * Pass certain directional keyboard events to the PDF viewer.
- * @param {Event} e The keydown event.
- */
-function tryToHandleDirectionKeyDown(e) {
- // Make sure the PDF plugin is there.
- if (!previewArea.pdfPlugin)
- return;
-
- // We only care about: PageUp, PageDown, Left, Up, Right, Down.
- if (!(e.keyCode == 33 || e.keyCode == 34 ||
- (e.keyCode >= 37 && e.keyCode <= 40))) {
- 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 (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'EMBED')
- 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)
+ this.printDocumentOrOpenPdfPreview_(true /*isPdfPreview*/);
+ },
+
+ /**
+ * Called when the print header's print button is clicked. Prints the
+ * document.
+ * @private
+ */
+ onPrintButtonClick_: function() {
+ assert(this.uiState_ == PrintPreview.UiState_.READY,
+ 'Trying to print when not in ready state: ' + this.uiState_);
+ this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
+ },
+
+ /**
+ * Called when the print header's cancel button is clicked. Closes the
+ * print dialog.
+ * @private
+ */
+ onCancelButtonClick_: function() {
+ this.close_();
+ },
+
+ /**
+ * Consume escape key presses and ctrl + shift + p. Delegate everything else
+ * to the preview area.
+ * @param {KeyboardEvent} e The keyboard event.
+ * @private
+ */
+ onKeyDown_: function(e) {
+ // Escape key closes the dialog.
+ if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey &&
+ !e.metaKey) {
+ this.close_();
+ e.preventDefault();
return;
- element = element.parentElement;
+ }
+
+ // Ctrl + Shift + p / Mac equivalent.
+ if (e.keyCode == 80) {
+ if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) ||
+ (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) {
+ this.openSystemPrintDialog_();
+ e.preventDefault();
+ return;
+ }
+ }
+
+ // Pass certain directional keyboard events to the PDF viewer.
+ this.previewArea_.handleDirectionalKeyEvent(e);
+ },
+
+ /**
+ * Called when native layer receives invalid settings for a print request.
+ * @private
+ */
+ onSettingsInvalid_: function() {
+ this.uiState_ = PrintPreview.UiState_.ERROR;
+ this.previewArea_.showCustomMessage(
+ localStrings.getString('invalidPrinterSettings'));
+ },
+
+ /**
+ * Called when the native layer dispatches a DISABLE_SCALING event. Updates
+ * the print ticket.
+ * @private
+ */
+ onDisableScaling_: function() {
+ this.printTicketStore_.updateFitToPage(false);
+ },
+
+ /**
+ * Called when the user selects the "Manage printers..." option in the
+ * destination select.
+ * @private
+ */
+ onManagePrinters_: function() {
+ if (cr.isChromeOS) {
+ this.nativeLayer_.startManageCloudPrinters();
+ } else {
+ this.nativeLayer_.startManageLocalPrinters();
+ }
}
- }
-
- // No scroll bar anywhere, or the active element is something else, like a
- // button. Note: buttons have a bigger scrollHeight than clientHeight.
- previewArea.pdfPlugin.sendKeyEvent(e.keyCode);
- e.preventDefault();
-}
-
-/**
- * Handle keyboard events.
- * @param {KeyboardEvent} e The keyboard event.
- */
-function onKeyDown(e) {
- // Escape key closes the dialog.
- if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
- printHeader.disableCancelButton();
- closePrintPreviewTab();
- e.preventDefault();
- }
- // Ctrl + Shift + p / Mac equivalent.
- if (e.keyCode == 80) {
- if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) ||
- (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) {
- window.removeEventListener('keydown', onKeyDown);
- onSystemDialogLinkClicked();
- e.preventDefault();
- }
- }
-
- tryToHandleDirectionKeyDown(e);
-}
-
-window.addEventListener('DOMContentLoaded', onLoad);
-window.addEventListener('keydown', onKeyDown);
-
-/// Pull in all other scripts in a single shot.
+ };
+
+ // Export
+ return {
+ PrintPreview: PrintPreview
+ };
+});
+
+// Pull in all other scripts in a single shot.
+<include src="data/page_number_set.js"/>
+<include src="data/destination.js"/>
+<include src="data/local_parsers.js"/>
+<include src="data/cloud_parsers.js"/>
+<include src="data/chromium_capabilities.js"/>
+<include src="data/cloud_capabilities.js"/>
+<include src="data/destination_store.js"/>
+<include src="data/margins.js"/>
+<include src="data/document_info.js"/>
+<include src="data/printable_area.js"/>
+<include src="data/measurement_system.js"/>
+<include src="data/print_ticket_store.js"/>
+<include src="data/coordinate2d.js"/>
+<include src="data/size.js"/>
+<include src="data/capabilities_holder.js"/>
+
+<include src="data/ticket_items/ticket_item.js"/>
+
+<include src="data/ticket_items/custom_margins.js"/>
+<include src="data/ticket_items/collate.js"/>
+<include src="data/ticket_items/color.js"/>
+<include src="data/ticket_items/copies.js"/>
+<include src="data/ticket_items/duplex.js"/>
+<include src="data/ticket_items/header_footer.js"/>
+<include src="data/ticket_items/landscape.js"/>
+<include src="data/ticket_items/margins_type.js"/>
+<include src="data/ticket_items/page_range.js"/>
+<include src="data/ticket_items/fit_to_page.js"/>
+
+<include src="native_layer.js"/>
<include src="print_preview_animations.js"/>
-<include src="print_preview_cloud.js"/>
+<include src="cloud_print_interface.js"/>
<include src="print_preview_utils.js"/>
<include src="print_header.js"/>
-<include src="page_settings.js"/>
-<include src="copies_settings.js"/>
-<include src="header_footer_settings.js"/>
-<include src="fit_to_page_settings.js"/>
-<include src="layout_settings.js"/>
-<include src="color_settings.js"/>
-<include src="margin_settings.js"/>
-<include src="margin_textbox.js"/>
-<include src="margin_utils.js"/>
-<include src="margins_ui.js"/>
-<include src="margins_ui_pair.js"/>
-<include src="more_options.js"/>
-<include src="preview_area.js"/>
+
+<include src="settings/page_settings.js"/>
+<include src="settings/copies_settings.js"/>
+<include src="settings/layout_settings.js"/>
+<include src="settings/color_settings.js"/>
+<include src="settings/margin_settings.js"/>
+<include src="settings/destination_settings.js"/>
+<include src="settings/other_options_settings.js"/>
+
+<include src="previewarea/margin_control.js"/>
+<include src="previewarea/margin_control_container.js"/>
+<include src="previewarea/preview_area.js"/>
+<include src="preview_generator.js"/>
+
+var printPreview = new print_preview.PrintPreview();
diff --git a/chrome/browser/resources/print_preview/print_preview_cloud.js b/chrome/browser/resources/print_preview/print_preview_cloud.js
deleted file mode 100644
index 7c8b7c0..0000000
--- a/chrome/browser/resources/print_preview/print_preview_cloud.js
+++ /dev/null
@@ -1,455 +0,0 @@
-// 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('cloudprint', function() {
-
- // The URL to use to access the cloud print servers.
- // Set by a call to setBaseURL.
- var cloudPrintBaseURL = '';
-
- // Headers to set for most cloud print API calls.
- var xCloudPrintURLHeader = {'Content-Type':
- 'application/x-www-form-urlencoded',
- 'X-CloudPrint-Proxy': 'ChromePrintPreview'};
-
- // Headers to set when sending multipart data to cloud print APIs.
- // Currently only used when submitting a job.
- var xCloudPrintFormHeader = {'Content-Type':
- 'multipart/form-data; boundary=----CloudPrintFormBoundaryjc9wuprokl8i',
- 'X-CloudPrint-Proxy': 'ChromePrintPreview'};
-
- // The last received XSRF token. This should be sent with each request
- // to prevent XSRF.
- var lastXSRFToken = '';
-
- /**
- * Sets the base URL to be used for communicating with cloud print
- * servers.
- * @param {string} cloudPrintURL The URL to use.
- */
- function setBaseURL(cloudPrintURL) {
- cloudPrintBaseURL = cloudPrintURL;
- }
-
- /**
- * Gets the base URL to be used for communicating with cloud print
- * servers.
- * @return {string} The URL.
- */
- function getBaseURL() {
- return cloudPrintBaseURL;
- }
-
- /**
- * Extracts the XSRF token from each response to be used in the next
- * request.
- * @param {XMLHttpRequest} xhr The object used to make the request.
- * @return {string} The extracted XSRF token.
- */
- function extractXSRFtoken(xhr) {
- if (xhr.status == 200) {
- var result = JSON.parse(xhr.responseText);
- return result['xsrf_token'];
- } else {
- return null;
- }
- }
-
- /**
- * Makes a request to cloud print servers.
- * @param {string} method The HTTP method to be used.
- * @param {string} action The cloud print API to call.
- * @param {Array} headers Headers to send with the request.
- * @param {string} body Body to be sent with POST requests.
- * @param {function} callback Function to be called to process response.
- * @param {boolean} async True if we want the request made asyncronously.
- */
- function sendCloudPrintRequest(method,
- action,
- headers,
- params,
- body,
- callback) {
- var xhr = new XMLHttpRequest();
- if (callback != null) {
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- var updatedXSRFToken = extractXSRFtoken(xhr);
- if (updatedXSRFToken != null) {
- lastXSRFToken = updatedXSRFToken;
- }
- callback.call(this, xhr);
- }
- };
- }
- var url = cloudPrintBaseURL + '/' + action;
- if (params == null) {
- params = new Array;
- }
- if (lastXSRFToken.length != 0) {
- params.push('xsrf=' + lastXSRFToken);
- }
- if (params.length != 0) {
- url = url + '?';
- for (param in params) {
- url = url + params[param] + '&';
- }
- }
- xhr.open(method, url, true);
- xhr.withCredentials = true;
- if (headers) {
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- xhr.setRequestHeader(header, headers[header]);
- }
- }
- }
- xhr.send(body);
- return xhr;
- }
-
- /**
- * Parse the response from the fetchPrinters call.
- * @param {function} callback Function to be called to process response.
- * @param {XMLHttpRequest} xhr The object used to make the request.
- */
- function fetchPrintersResponse(callback, xhr) {
- if (xhr.status == 200) {
- var searchResult = JSON.parse(xhr.responseText);
- if (searchResult['success']) {
- var printerList = searchResult['printers'];
- addCloudPrinters(printerList, callback);
- return;
- }
- }
- addCloudPrinters(null, callback);
- }
-
- /**
- * Retrieve the list of printers available via cloud print.
- * @param {function} callback Function to be called to process response.
- */
- function fetchPrinters(callback, all) {
- var query = 'q=^recent';
- if (all) {
- query = '';
- }
- sendCloudPrintRequest('GET',
- 'search',
- xCloudPrintURLHeader,
- [query],
- null,
- fetchPrintersResponse.bind(this, callback));
- }
-
- /**
- * Handle the response from printing to cloud print.
- * @param {function} callback Function to be called to process response.
- * @param {XMLHttpRequest} xhr The object used to make the request.
- */
- function printToCloudResponse(callback, xhr) {
- if (xhr.status == 200) {
- var printResult = JSON.parse(xhr.responseText);
- if (printResult['success']) {
- callback.call();
- }
- }
- // TODO(abodenha@chromium.org) Catch and handle failures.
- }
-
- /**
- * Send the current document to cloud print.
- * @param {string} data The document to be printed.
- * @param {function} callback Function to be called to process response.
- */
- function printToCloud(data, callback) {
- // TODO(abodenha@chromium.org) Make sure we have an XSRF token before
- // sending a submit. Right now if the user clicks print before we
- // complete any request we wont have an XSRF and the submit will fail.
- sendCloudPrintRequest('POST',
- 'submit',
- xCloudPrintFormHeader,
- null,
- data,
- printToCloudResponse.bind(this, callback));
- }
-
- /**
- * Gets the JSON string used to control the behavior of the current
- * print job.
- * @param {Object} printer The printer object to get the ticket for.
- * @return {string} The print ticket or null if not a cloud printer.
- */
- function getPrintTicketJSON(printer) {
- if (isCloudPrint(printer)) {
- return JSON.stringify({'capabilities':
- [printer.cloudPrintOptions.colorOption]});
- } else {
- return null;
- }
- }
-
- /**
- * Process the response from cloud print containing the capabilities
- * for the printer.
- * @param {function} callback Function to be called to process response.
- * @param {Object} printer The printer object to get the capabilites for.
- * @param {XMLHttpRequest} xhr The object used to make the request.
- */
- function updatePrinterCapsResponse(callback, printer, xhr) {
- if (xhr.status == 200) {
- var printResult = JSON.parse(xhr.responseText);
- if (printResult['success']) {
- if (!printer.cloudPrintOptions)
- printer.cloudPrintOptions = new Object;
- printer.cloudPrintOptions.capsDownloaded = true;
- printer.cloudPrintOptions.colorOption = null;
- printer.cloudPrintOptions.colorIsDefault = false;
- var detailedCapabilities = printResult.printers[0].capabilities;
- for (var capability in detailedCapabilities) {
- var cap = detailedCapabilities[capability];
- if (cap.name == 'ns1:Colors') {
- printer.cloudPrintOptions.colorOption = new Object;
- printer.cloudPrintOptions.colorOption.name = cap.name;
- printer.cloudPrintOptions.colorOption.type = cap.type;
- for (var option in cap.options) {
- var opt = cap.options[option];
- if (opt.name == 'Color') {
- printer.cloudPrintOptions.colorOnOption = opt;
- }
- if (opt.name == 'Grey_K') {
- printer.cloudPrintOptions.colorOffOption = opt;
- }
- if (opt.default) {
- printer.cloudPrintOptions.colorOption.options = [opt];
- printer.cloudPrintOptions.colorIsDefault =
- opt.name == printer.cloudPrintOptions.colorOnOption.name;
- }
- }
- }
- }
- callback.call(this, printer);
- }
- }
- }
-
- /**
- * Retrieve capabilities for a printer.
- * @param {Object} printer The printer object to get the capabilities for.
- * @param {function} callback Function to be called to process response.
- */
- function updatePrinterCaps(printer, callback) {
- if (isCloudPrint(printer) && !printer.cloudPrintOptions.capsDownloaded) {
- sendCloudPrintRequest('GET',
- 'printer?printerid=' +
- printer.value +
- '&output=json',
- xCloudPrintURLHeader,
- null,
- null,
- updatePrinterCapsResponse.bind(this,
- callback,
- printer));
- } else {
- callback.call(this, printer);
- }
- }
-
- /**
- * @param {Object} printer The printer object to get the data for.
- * @return {boolean} true if the printer supports color.
- */
- function supportsColor(printer) {
- return isCloudPrint(printer) &&
- printer.cloudPrintOptions.colorOption != null;
- }
-
- /**
- * @param {Object} printer The printer object to get the data for.
- * @return {boolean} true if the printer defaults to color.
- */
- function colorIsDefault(printer) {
- // For now assume that unsupported color means we just don't know
- // and assume color.
- return !supportsColor(printer) ||
- (isCloudPrint(printer) && printer.cloudPrintOptions.colorIsDefault);
- }
-
- /**
- * Turn color on or off for the specified printer.
- * @param {Object} printer The printer object to turn color on/off for.
- * @param {boolean} color True to turn color on.
- */
- function setColor(printer, color) {
- if (isCloudPrint(printer) && supportsColor(printer)) {
- if (color) {
- printer.cloudPrintOptions.colorOption.options =
- [printer.cloudPrintOptions.colorOnOption];
- } else {
- printer.cloudPrintOptions.colorOption.options =
- [printer.cloudPrintOptions.colorOffOption];
- }
- }
- }
-
- /**
- * Creates a cloud print printer and sets it as the default printer.
- * @param {string} printer_name The name of the printer to create.
- * @param {Object} cloud_print_data Data to be stored in cloudPrintOptions.
- * @param {function} add_callback The callback to be called to add the new
- * printer to the print preview UI.
- * @param {function} update_caps_callback The callback to be called to update
- * capabilities on the new printer.
- */
- function setDefaultPrinter(printer_name,
- cloud_print_data,
- add_callback,
- update_caps_callback) {
- var printer = addCloudPrinters([JSON.parse(cloud_print_data)],
- add_callback);
- if (printer)
- update_caps_callback(printer);
- }
-
- /**
- * Returns the data necessary to serialize a cloud print printer.
- * @param {Object} printer The printer object to get data for.
- * @return {string} A JSON string that can be used to recreate the
- * cloud print portion of the printer object, or and empty string if
- * there is no data to save.
- */
- function getData(printer) {
- if (isCloudPrint(printer)) {
- return JSON.stringify(printer.cloudPrintOptions);
- } else {
- return '';
- }
- }
-
- /**
- * Test if a printer is a cloud print printer.
- * @param {Object} printer The printer to test.
- * @return {boolean} true iff the printer is a cloud print printer.
- */
- function isCloudPrint(printer) {
- return printer && printer.cloudPrintOptions != null;
- }
-
- /**
- * Mark a printer as a cloud print printer and record its name and id.
- * @param {Object} printer The printer to mark.
- * @param {string} name The user visible name of the printer.
- * @param {string} id The id of the printer used by cloud print to
- * identify it.
- */
- function setCloudPrint(printer, name, id) {
- if (!printer.cloudPrintOptions) {
- printer.cloudPrintOptions = new Object;
- }
- printer.cloudPrintOptions.name = name;
- printer.cloudPrintOptions.id = id;
- }
-
- /**
- * Test if a particular cloud printer has already been added to the
- * printer dropdown.
- * @param {string} id A unique value to track this printer.
- * @return {boolean} True if |id| has previously been passed to
- * trackCloudPrinterAdded.
- */
- function cloudPrinterAlreadyAdded(id) {
- return addedCloudPrinters[id];
- }
-
- /**
- * Test if a particular printer has already been added to the printers
- * dropdown. Records it if not.
- * @param {string} id A unique value to track this printer.
- * @return {boolean} False if adding this printer would exceed
- * |maxCloudPrinters|.
- */
- function trackCloudPrinterAdded(id) {
- if (Object.keys(addedCloudPrinters).length < maxCloudPrinters) {
- addedCloudPrinters[id] = true;
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Add cloud printers to the list drop down.
- * Called from the cloudprint object on receipt of printer information from
- * the cloud print server.
- * @param {Array} printers Array of printer info objects.
- * @return {Object} The currently selected printer.
- */
- function addCloudPrinters(printers, addDestinationListOptionAtPosition) {
- var isFirstPass = false;
- var printerList = $('printer-list');
-
- if (firstCloudPrintOptionPos == lastCloudPrintOptionPos) {
- isFirstPass = true;
- // Remove empty entry added by setDefaultPrinter.
- if (printerList[0] && printerList[0].textContent == '')
- printerList.remove(0);
- }
- if (printers != null) {
- for (var i = 0; i < printers.length; i++) {
- if (!cloudPrinterAlreadyAdded(printers[i]['id'])) {
- if (!trackCloudPrinterAdded(printers[i]['id'])) {
- break;
- }
- if (printers[i]['displayName'] && printers[i]['displayName'] != '')
- var name = printers[i]['displayName'];
- else
- var name = printers[i]['name'];
-
- var option = addDestinationListOptionAtPosition(
- lastCloudPrintOptionPos++,
- name,
- printers[i]['id'],
- name == defaultOrLastUsedPrinterName,
- false,
- false);
- cloudprint.setCloudPrint(option,
- name,
- printers[i]['id']);
- }
- }
- } else {
- if (!cloudPrinterAlreadyAdded(SIGN_IN)) {
- addDestinationListOptionAtPosition(lastCloudPrintOptionPos++,
- localStrings.getString('signIn'),
- SIGN_IN,
- false,
- false,
- false);
- trackCloudPrinterAdded(SIGN_IN);
- chrome.send('signIn');
- }
- }
- var selectedPrinter = printerList.selectedIndex;
- if (selectedPrinter < 0)
- return null;
- return printerList.options[selectedPrinter];
- }
-
- return {
- addCloudPrinters: addCloudPrinters,
- colorIsDefault: colorIsDefault,
- fetchPrinters: fetchPrinters,
- getBaseURL: getBaseURL,
- getData: getData,
- getPrintTicketJSON: getPrintTicketJSON,
- isCloudPrint: isCloudPrint,
- printToCloud: printToCloud,
- setBaseURL: setBaseURL,
- setCloudPrint: setCloudPrint,
- setColor: setColor,
- setDefaultPrinter: setDefaultPrinter,
- supportsColor: supportsColor,
- updatePrinterCaps: updatePrinterCaps
- };
-});
diff --git a/chrome/browser/resources/print_preview/print_preview_utils.js b/chrome/browser/resources/print_preview/print_preview_utils.js
index c761650..35bb80a 100644
--- a/chrome/browser/resources/print_preview/print_preview_utils.js
+++ b/chrome/browser/resources/print_preview/print_preview_utils.js
@@ -187,81 +187,19 @@ function pageSetToPageRanges(pageSet) {
}
/**
- * Constructs a url for getting a specific page.
- * @param {string} id The id of the preview data.
- * @param {number} pageNumber The number of the desired page.
- * @return {string} The constructed URL.
+ * Shows or hides an element.
+ * @param {Element} element Element to show or hide.
+ * @param {boolean} isVisible Whether the element should be visible or not.
*/
-function getPageSrcURL(id, pageNumber) {
- return 'chrome://print/' + id + '/' + pageNumber + '/print.pdf';
+function setIsVisible(element, isVisible) {
+ element.style.display = isVisible ? '' : 'none';
}
/**
- * Returns a random integer within the specified range, |endPointA| and
- * |endPointB| are included.
- * @param {number} endPointA One end of the desired range.
- * @param {number} endPointB The other end of the desired range.
- * @return {number} The random integer.
+ * @param {Array.<object>} array Array to check for item.
+ * @param {object} item Item to look for in array.
+ * @return {boolean} Whether the item is in the array.
*/
-function randomInteger(endPointA, endPointB) {
- var from = Math.min(endPointA, endPointB);
- var to = Math.max(endPointA, endPointB);
- return Math.floor(Math.random() * (to - from + 1) + from);
-}
-
-// Number of points per inch.
-var POINTS_PER_INCH = 72;
-// Number of points per millimeter.
-var POINTS_PER_MILLIMETER = 2.83464567;
-
-/**
- * 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;
-}
-
-/**
- * Converts |value| from millimeters to points.
- * @param {number} value The number in millimeters.
- * @return {number} |value| in points.
- */
-function convertMillimetersToPoints(value) {
- return value * POINTS_PER_MILLIMETER;
-}
-
-/**
- * Converts |value| from points to millimeters.
- * @param {number} value The number in points.
- * @return {number} |value| in millimeters.
- */
-function convertPointsToMillimeters(value) {
- return value / POINTS_PER_MILLIMETER;
-}
-
-/**
- * Parses |numberFormat| and extracts the symbols used for the thousands point
- * and decimal point.
- * @param {string} numberFormat The formatted version of the number 12345678.
- * @return {!Array.<string>} The extracted symbols in the order
- * [thousandsSymbol, decimalSymbol]]. For example
- * parseNumberFormat("123,456.78") returns [",", "."].
- */
-function parseNumberFormat(numberFormat) {
- if (!numberFormat)
- numberFormat = '';
- var regex = /^(\d+)(\W{0,1})(\d+)(\W{0,1})(\d+)$/;
- var matches = numberFormat.match(regex) || ['', '', ',', '', '.'];
- return [matches[2], matches[4]];
+function arrayContains(array, item) {
+ return array.indexOf(item) != -1;
}
diff --git a/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs b/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
index adaee85..5f674b7 100644
--- a/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
+++ b/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -7,7 +7,9 @@
* @constructor
* @extends {testing.Test}
*/
-function PrintPreviewUtilsUnitTest () {}
+function PrintPreviewUtilsUnitTest () {
+ testing.Test.call(this);
+}
PrintPreviewUtilsUnitTest.prototype = {
__proto__: testing.Test.prototype,
@@ -15,7 +17,7 @@ PrintPreviewUtilsUnitTest.prototype = {
/** @inheritDoc */
extraLibraries: [
'print_preview_utils.js',
- ],
+ ]
};
TEST_F('PrintPreviewUtilsUnitTest', 'IsInteger', function() {
@@ -113,21 +115,3 @@ TEST_F('PrintPreviewUtilsUnitTest', 'PageSetToPageRanges', function() {
assertEquals(pageRanges[2].from, 11);
assertEquals(pageRanges[2].to, 11);
});
-
-TEST_F('PrintPreviewUtilsUnitTest', 'ParseNumberFormat', function() {
- assertTrue(areArraysEqual(['.', ','], parseNumberFormat('123.456,78')));
- assertTrue(areArraysEqual(['.', '.'], parseNumberFormat('123.456.78')));
- assertTrue(areArraysEqual([',', '.'], parseNumberFormat('123,456.78')));
- assertTrue(areArraysEqual([',', ','], parseNumberFormat('123,456,78')));
- assertTrue(areArraysEqual([' ', ','], parseNumberFormat('123 456,78')));
- assertTrue(areArraysEqual([' ', '.'], parseNumberFormat('123 456.78')));
- assertTrue(areArraysEqual([' ', ' '], parseNumberFormat('123 456 78')));
- assertTrue(areArraysEqual(['', ''], parseNumberFormat('123')));
-
- assertTrue(areArraysEqual([',', '.'], parseNumberFormat('abcdef')));
- assertTrue(areArraysEqual([',', '.'], parseNumberFormat(null)));
- assertTrue(areArraysEqual([',', '.'], parseNumberFormat(undefined)));
- assertTrue(areArraysEqual([',', '.'], parseNumberFormat('')));
- assertTrue(areArraysEqual([',', '.'], parseNumberFormat('1')));
- assertTrue(areArraysEqual([',', '.'], parseNumberFormat('12')));
-});
diff --git a/chrome/browser/resources/print_preview/settings/color_settings.html b/chrome/browser/resources/print_preview/settings/color_settings.html
new file mode 100644
index 0000000..7b742e9
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/color_settings.html
@@ -0,0 +1,17 @@
+<div id="color-settings"
+ class="color-settings two-column visible"
+ aria-hidden="false"
+ aria-live="polite">
+ <h1 i18n-content="optionColor"></h1>
+ <div class="right-column">
+ <div class="radio"><label>
+ <input class="color-settings-color-option" type="radio" name="color"/>
+ <span i18n-content="optionColor"></span>
+ </label></div>
+ <div class="radio"><label>
+ <input class="color-settings-bw-option" type="radio" name="color"
+ checked/>
+ <span i18n-content="optionBw"></span>
+ </label></div>
+ </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/settings/color_settings.js b/chrome/browser/resources/print_preview/settings/color_settings.js
new file mode 100644
index 0000000..eb35e65
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/color_settings.js
@@ -0,0 +1,133 @@
+// 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 ColorSettings object. This object encapsulates all settings and
+ * logic related to color selection (color/bw).
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used for writing
+ * to the print ticket.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function ColorSettings(printTicketStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used for writing to the print ticket.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+ };
+
+ /**
+ * CSS classes used by the color settings.
+ * @enum {string}
+ * @private
+ */
+ ColorSettings.Classes_ = {
+ BW_OPTION: 'color-settings-bw-option',
+ COLOR_OPTION: 'color-settings-color-option'
+ };
+
+ ColorSettings.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ set isEnabled(isEnabled) {
+ this.colorRadioButton_.disabled = !isEnabled;
+ this.bwRadioButton_.disabled = !isEnabled;
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.addEventListeners_();
+ },
+
+ get colorRadioButton_() {
+ return this.getElement().getElementsByClassName(
+ ColorSettings.Classes_.COLOR_OPTION)[0];
+ },
+
+ get bwRadioButton_() {
+ return this.getElement().getElementsByClassName(
+ ColorSettings.Classes_.BW_OPTION)[0];
+ },
+
+ /**
+ * Adding listeners to all targets and UI controls.
+ * @private
+ */
+ addEventListeners_: function() {
+ this.tracker.add(
+ this.colorRadioButton_,
+ 'click',
+ this.updatePrintTicket_.bind(this, true));
+ this.tracker.add(
+ this.bwRadioButton_,
+ 'click',
+ this.updatePrintTicket_.bind(this, false));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.INITIALIZE,
+ this.onCapabilitiesChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.onCapabilitiesChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onCapabilitiesChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onTicketChange_.bind(this));
+ },
+
+ /**
+ * Updates print ticket with whether the document should be printed in
+ * color.
+ * @param {boolean} isColor Whether the document should be printed in color.
+ * @private
+ */
+ updatePrintTicket_: function(isColor) {
+ this.printTicketStore_.updateColor(isColor);
+ },
+
+ /**
+ * Called when the ticket store's capabilities have changed. Shows or hides
+ * the color settings.
+ * @private
+ */
+ onCapabilitiesChange_: function() {
+ if (this.printTicketStore_.hasColorCapability()) {
+ fadeInOption(this.getElement());
+ var isColorEnabled = this.printTicketStore_.isColorEnabled();
+ this.colorRadioButton_.checked = isColorEnabled;
+ this.bwRadioButton_.checked = !isColorEnabled;
+ } else {
+ fadeOutOption(this.getElement());
+ }
+ this.getElement().setAttribute(
+ 'aria-hidden', !this.printTicketStore_.hasColorCapability());
+ },
+
+ onTicketChange_: function() {
+ if (this.printTicketStore_.hasColorCapability()) {
+ var isColorEnabled = this.printTicketStore_.isColorEnabled();
+ this.colorRadioButton_.checked = isColorEnabled;
+ this.bwRadioButton_.checked = !isColorEnabled;
+ }
+ }
+ };
+
+ // Export
+ return {
+ ColorSettings: ColorSettings
+ };
+});
diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.css b/chrome/browser/resources/print_preview/settings/copies_settings.css
new file mode 100644
index 0000000..129943f
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/copies_settings.css
@@ -0,0 +1,56 @@
+/* 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.
+ */
+
+#copies-settings .copies-settings-copies {
+ position: relative;
+ width: 2.75em;
+}
+
+#copies-settings .copies-settings-copies.invalid {
+ background: rgb(255, 240, 240);
+ color: rgb(140, 20, 20);
+}
+
+#copies-settings .copies-settings-increment:focus,
+#copies-settings .copies-settings-decrement:focus,
+.copies-settings:focus {
+ z-index: 1;
+}
+
+#copies-settings .copies-settings-collate {
+ -webkit-padding-start: 16px;
+ display: inline-block;
+}
+
+#copies-settings .copies-settings-increment,
+#copies-settings .copies-settings-decrement {
+ -webkit-padding-end: 0;
+ -webkit-padding-start: 0;
+ font-weight: 600;
+ margin: 0;
+ min-width: 0;
+ position: relative;
+ width: 2em;
+}
+
+#copies-settings .copies-settings-increment {
+ -webkit-margin-start: -5px;
+ border-radius: 0;
+}
+
+#copies-settings .copies-settings-decrement {
+ -webkit-margin-start: -5px;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 3px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 3px;
+}
+
+html[dir='rtl'] #copies-settings .copies-settings-decrement {
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 0;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 0;
+}
diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.html b/chrome/browser/resources/print_preview/settings/copies_settings.html
new file mode 100644
index 0000000..b8218df
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/copies_settings.html
@@ -0,0 +1,31 @@
+<div id="copies-settings" class="copies-settings two-column visible">
+ <h1 i18n-content="copiesLabel"></h1>
+ <div class="right-column">
+ <div>
+ <input class="copies-settings-copies" type="text" value="1" maxlength="3">
+ <button class="copies-settings-increment"
+ i18n-values="title:incrementTitle;">+</button>
+ <button class="copies-settings-decrement"
+ i18n-values="title:decrementTitle;">–</button>
+ <div class="copies-settings-collate checkbox"
+ aria-live="polite" hidden>
+ <label>
+ <input class="copies-settings-collate-checkbox"
+ type="checkbox"
+ checked/>
+ <span i18n-content="optionCollate"></span>
+ </label>
+ </div>
+ </div>
+ <span class="copies-settings-hint hint"
+ i18n-content="copiesInstruction"
+ aria-live="polite">
+ </span>
+ <div class="checkbox">
+ <label class="copies-settings-duplex" aria-live="polite">
+ <input class="copies-settings-duplex-checkbox" type="checkbox"/>
+ <span i18n-content="optionTwoSided"></span>
+ </label>
+ </div>
+ </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.js b/chrome/browser/resources/print_preview/settings/copies_settings.js
new file mode 100644
index 0000000..f2baecd
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/copies_settings.js
@@ -0,0 +1,327 @@
+// 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';
+
+ /**
+ * Component that renders the copies settings UI.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to read and
+ * write the copies settings.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function CopiesSettings(printTicketStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used for writing to the print ticket and validating inputted values.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+
+ /**
+ * Timeout used to delay processing of the copies input.
+ * @type {Object}
+ * @private
+ */
+ this.textfieldTimeout_ = null;
+
+ /**
+ * Whether this component is enabled or not.
+ * @type {boolean}
+ * @private
+ */
+ this.isEnabled_ = true;
+
+ /**
+ * Textfield for entering copies values.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.textfield_ = null;
+
+ /**
+ * Increment button used to increment the copies value.
+ * @type {HTMLButtonElement}
+ * @private
+ */
+ this.incrementButton_ = null;
+
+ /**
+ * Decrement button used to decrement the copies value.
+ * @type {HTMLButtonElement}
+ * @private
+ */
+ this.decrementButton_ = null;
+
+ /**
+ * Container div for the collate checkbox.
+ * @type {HTMLDivElement}
+ * @private
+ */
+ this.collateDiv_ = null;
+
+ /**
+ * Checkbox used to enable/disable collation.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.collateCheckbox_ = null;
+
+ /**
+ * Container div for the duplex checkbox.
+ * @type {HTMLDivElement}
+ * @private
+ */
+ this.duplexDiv_ = null;
+
+ /**
+ * Checkbox used to enable/disable duplexing.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.duplexCheckbox_ = null;
+
+ /**
+ * Hint element used to show a hint when the copies value is invalid.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.hintEl_ = null;
+ };
+
+ /**
+ * CSS classes used by the component.
+ * @enum {string}
+ * @private
+ */
+ CopiesSettings.Classes_ = {
+ COPIES: 'copies-settings-copies',
+ INCREMENT: 'copies-settings-increment',
+ DECREMENT: 'copies-settings-decrement',
+ HINT: 'copies-settings-hint',
+ COLLATE: 'copies-settings-collate',
+ COLLATE_CHECKBOX: 'copies-settings-collate-checkbox',
+ DUPLEX: 'copies-settings-duplex',
+ DUPLEX_CHECKBOX: 'copies-settings-duplex-checkbox'
+ };
+
+ /**
+ * Delay in milliseconds before processing the textfield.
+ * @type {number}
+ * @private
+ */
+ CopiesSettings.TEXTFIELD_DELAY_ = 250;
+
+ CopiesSettings.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ /** @param {boolean} isEnabled Whether the copies settings is enabled. */
+ set isEnabled(isEnabled) {
+ this.textfield_.disabled = !isEnabled;
+ this.collateCheckbox_.disabled = !isEnabled;
+ this.duplexCheckbox_.disabled = !isEnabled;
+ this.isEnabled_ = isEnabled;
+ if (isEnabled) {
+ this.updateState_();
+ } else {
+ this.textfield_.disabled = true;
+ this.incrementButton_.disabled = true;
+ this.decrementButton_.disabled = true;
+ this.duplexCheckbox_.disabled = true;
+ }
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+
+ this.tracker.add(
+ this.textfield_, 'keyup', this.onTextfieldKeyUp_.bind(this));
+ this.tracker.add(
+ this.textfield_, 'blur', this.onTextfieldBlur_.bind(this));
+ this.tracker.add(
+ this.incrementButton_, 'click', this.onButtonClicked_.bind(this, 1));
+ this.tracker.add(
+ this.decrementButton_, 'click', this.onButtonClicked_.bind(this, -1));
+ this.tracker.add(
+ this.duplexCheckbox_,
+ 'click',
+ this.onDuplexCheckboxClick_.bind(this));
+ this.tracker.add(
+ this.collateCheckbox_,
+ 'click',
+ this.onCollateCheckboxClick_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.INITIALIZE,
+ this.updateState_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.updateState_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.updateState_.bind(this));
+ },
+
+ /** @override */
+ exitDocument: function() {
+ print_preview.Component.prototype.exitDocument.call(this);
+ this.textfield_ = null;
+ this.incrementButton_ = null;
+ this.decrementButton_ = null;
+ this.collateDiv_ = null;
+ this.collateCheckbox_ = null;
+ this.duplexDiv_ = null;
+ this.duplexCheckbox_ = null;
+ this.hintEl_ = null;
+ },
+
+ /** @override */
+ decorateInternal: function() {
+ this.textfield_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.COPIES)[0];
+ this.incrementButton_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.INCREMENT)[0];
+ this.decrementButton_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.DECREMENT)[0];
+ this.collateDiv_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.COLLATE)[0];
+ this.collateCheckbox_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.COLLATE_CHECKBOX)[0];
+ this.duplexDiv_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.DUPLEX)[0];
+ this.duplexCheckbox_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.DUPLEX_CHECKBOX)[0];
+ this.hintEl_ = this.getElement().getElementsByClassName(
+ CopiesSettings.Classes_.HINT)[0];
+ },
+
+ /**
+ * Updates the state of the copies settings UI controls.
+ * @private
+ */
+ updateState_: function() {
+ if (!this.printTicketStore_.hasCopiesCapability()) {
+ fadeOutOption(this.getElement());
+ return;
+ }
+
+ if (this.textfield_.value != this.printTicketStore_.getCopiesStr()) {
+ this.textfield_.value = this.printTicketStore_.getCopiesStr();
+ }
+
+ var currentValueGreaterThan1 = false;
+ if (this.printTicketStore_.isCopiesValid()) {
+ this.textfield_.classList.remove('invalid');
+ fadeOutElement(this.hintEl_);
+ this.hintEl_.setAttribute('aria-hidden', true);
+ var currentValue = parseInt(this.printTicketStore_.getCopiesStr());
+ var currentValueGreaterThan1 = currentValue > 1;
+ this.incrementButton_.disabled =
+ !this.isEnabled_ ||
+ !this.printTicketStore_.isCopiesValidForValue(currentValue + 1);
+ this.decrementButton_.disabled =
+ !this.isEnabled_ ||
+ !this.printTicketStore_.isCopiesValidForValue(currentValue - 1);
+ } else {
+ this.textfield_.classList.add('invalid');
+ this.hintEl_.setAttribute('aria-hidden', false);
+ fadeInElement(this.hintEl_);
+ this.incrementButton_.disabled = true;
+ this.decrementButton_.disabled = true;
+ }
+
+ if (!(this.collateDiv_.hidden =
+ !this.printTicketStore_.hasCollateCapability() ||
+ !currentValueGreaterThan1)) {
+ this.collateCheckbox_.checked =
+ this.printTicketStore_.isCollateEnabled();
+ }
+
+ // On Windows, some printers don't specify their duplex values in the
+ // printer schema. If the printer duplex value is UNKNOWN_DUPLEX_MODE,
+ // hide the two sided option in preview tab UI.
+ // Ref bug: http://crbug.com/89204
+ if (!(this.duplexDiv_.hidden =
+ !this.printTicketStore_.hasDuplexCapability())) {
+ this.duplexCheckbox_.checked = this.printTicketStore_.isDuplexEnabled();
+ }
+
+ fadeInOption(this.getElement());
+ },
+
+ /**
+ * Called when the duplex checkbox changes state. Updates the print ticket.
+ * @private
+ */
+ onDuplexCheckboxClick_: function() {
+ this.printTicketStore_.updateDuplex(this.duplexCheckbox_.checked);
+ },
+
+ /**
+ * Called whenever the increment/decrement buttons are clicked.
+ * @param {number} delta Must be 1 for an increment button click and -1 for
+ * a decrement button click.
+ * @private
+ */
+ onButtonClicked_: function(delta) {
+ // Assumes text field has a valid number.
+ var newValue = parseInt(this.textfield_.value) + delta;
+ this.printTicketStore_.updateCopies(newValue);
+ },
+
+ /**
+ * Called after a timeout after user input into the textfield.
+ * @private
+ */
+ onTextfieldTimeout_: function() {
+ if (this.textfield_ != '') {
+ this.printTicketStore_.updateCopies(this.textfield_.value);
+ }
+ },
+
+ /**
+ * Called when a keyup event occurs on the textfield. Starts an input
+ * timeout.
+ * @param {Event} event Contains the pressed key.
+ * @private
+ */
+ onTextfieldKeyUp_: function(event) {
+ if (this.textfieldTimeout_) {
+ clearTimeout(this.textfieldTimeout_);
+ }
+ this.textfieldTimeout_ = setTimeout(
+ this.onTextfieldTimeout_.bind(this), CopiesSettings.TEXTFIELD_DELAY_);
+ },
+
+ /**
+ * Called when the focus leaves the textfield. If the textfield is empty,
+ * its value is set to 1.
+ * @private
+ */
+ onTextfieldBlur_: function() {
+ if (this.textfield_.value == '') {
+ this.printTicketStore_.updateCopies('1');
+ }
+ },
+
+ /**
+ * Called when the collate checkbox is clicked. Updates the print ticket.
+ * @private
+ */
+ onCollateCheckboxClick_: function() {
+ this.printTicketStore_.updateCollate(this.collateCheckbox_.checked);
+ }
+ };
+
+ // Export
+ return {
+ CopiesSettings: CopiesSettings
+ };
+});
diff --git a/chrome/browser/resources/print_preview/settings/destination_settings.html b/chrome/browser/resources/print_preview/settings/destination_settings.html
new file mode 100644
index 0000000..55a9e47
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/destination_settings.html
@@ -0,0 +1,6 @@
+<div id="destination-settings" class="two-column visible">
+ <h1 i18n-content="destinationLabel"></h1>
+ <div class="right-column">
+ <select class="destination-settings-select"></select>
+ </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/settings/destination_settings.js b/chrome/browser/resources/print_preview/settings/destination_settings.js
new file mode 100644
index 0000000..4713d0a
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/destination_settings.js
@@ -0,0 +1,199 @@
+// 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';
+
+ // TODO(rltoscano): This class needs a throbber while loading the destination
+ // or another solution is persist the settings of the printer so that next
+ // load is fast.
+
+ /**
+ * Component used to render the print destination.
+ * @param {!print_preview.DestinationStore} destinationStore Used to determine
+ * the selected destination.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function DestinationSettings(destinationStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to determine the selected destination.
+ * @type {!print_preview.DestinationStore}
+ * @private
+ */
+ this.destinationStore_ = destinationStore;
+ };
+
+ /**
+ * Event types dispatched by the component.
+ * @enum {string}
+ */
+ DestinationSettings.EventType = {
+ MANAGE_PRINTERS_SELECT:
+ 'print_preview.DestinationSettings.MANAGE_PRINTERS_SELECT'
+ };
+
+ /**
+ * CSS classes used by the component.
+ * @enum {string}
+ * @private
+ */
+ DestinationSettings.Classes_ = {
+ SELECT: 'destination-settings-select'
+ };
+
+ /**
+ * Option value of the "Manage Printers..." select option.
+ * @type {string}
+ * @const
+ * @private
+ */
+ DestinationSettings.MANAGE_ID_ = '__manage';
+
+ DestinationSettings.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ set isEnabled(isEnabled) {
+ this.select_.disabled = !isEnabled;
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.tracker.add(
+ this.select_, 'change', this.onSelectChange_.bind(this));
+ this.tracker.add(
+ this.destinationStore_,
+ print_preview.DestinationStore.EventType.DESTINATION_SELECT,
+ this.onDestinationSelect_.bind(this));
+ this.tracker.add(
+ this.destinationStore_,
+ print_preview.DestinationStore.EventType.DESTINATIONS_INSERTED,
+ this.onDestinationsInserted_.bind(this));
+ },
+
+ get select_() {
+ return this.getElement().getElementsByClassName(
+ DestinationSettings.Classes_.SELECT)[0];
+ },
+
+ renderDestinations_: function() {
+ var select = this.select_;
+ select.innerHTML = '';
+ var destinations = this.destinationStore_.destinations;
+ var selectedDestination = this.destinationStore_.selectedDestination;
+ var saveToPdfDest = null;
+ var printWithCloudPrintDest = null;
+ for (var dest, i = 0; dest = destinations[i]; i++) {
+ if (dest.id == print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
+ saveToPdfDest = dest;
+ continue;
+ }
+ if (dest.isPrintWithCloudPrint) {
+ printWithCloudPrintDest = dest;
+ continue;
+ }
+ var optionEl = document.createElement('option');
+ optionEl.value = dest.id;
+ optionEl.selected =
+ selectedDestination && selectedDestination.id == dest.id;
+ optionEl.textContent = dest.displayName;
+ select.appendChild(optionEl);
+ }
+
+ // Add special destinations.
+ if (saveToPdfDest) {
+ select.appendChild(this.createSeparatorOption_());
+ var printToPdfOptionEl = document.createElement('option');
+ printToPdfOptionEl.value = saveToPdfDest.id;
+ printToPdfOptionEl.selected =
+ selectedDestination && selectedDestination.id == saveToPdfDest.id;
+ printToPdfOptionEl.textContent = saveToPdfDest.displayName;
+ select.appendChild(printToPdfOptionEl);
+ }
+ if (printWithCloudPrintDest) {
+ select.appendChild(this.createSeparatorOption_());
+ var printWithCloudPrintOptionEl = document.createElement('option');
+ printWithCloudPrintOptionEl.value = printWithCloudPrintDest.id;
+ printWithCloudPrintOptionEl.selected =
+ selectedDestination &&
+ selectedDestination.id == printWithCloudPrintDest.id;
+ printWithCloudPrintOptionEl.textContent =
+ printWithCloudPrintDest.displayName;
+ select.appendChild(printWithCloudPrintOptionEl);
+ }
+ select.appendChild(this.createSeparatorOption_());
+ var manageOptionEl = document.createElement('option');
+ manageOptionEl.value = DestinationSettings.MANAGE_ID_;
+ manageOptionEl.textContent = localStrings.getString('managePrinters');
+ select.appendChild(manageOptionEl);
+ },
+
+ createSeparatorOption_: function() {
+ var sep = document.createElement('option');
+ sep.disabled = true;
+ sep.role = 'separator';
+ return sep;
+ },
+
+ /**
+ * Called when a destination is selected. Selects the corresponding option.
+ * @private
+ */
+ onDestinationSelect_: function() {
+ var select = this.select_;
+ if (select.options.length > 0) {
+ select.options[select.selectedIndex].selected = false;
+ }
+ var selectedDestination = this.destinationStore_.selectedDestination;
+ for (var option, i = 0; option = select.options[i]; i++) {
+ if (selectedDestination.id == option.value) {
+ option.selected = true;
+ break;
+ }
+ }
+ },
+
+ /**
+ * Called when destinations are inserted into the destination store. Updates
+ * the select element.
+ * @private
+ */
+ onDestinationsInserted_: function() {
+ this.renderDestinations_();
+ },
+
+ /**
+ * Called when the select element changes options. Selects the corresponding
+ * print destination.
+ * @private
+ */
+ onSelectChange_: function() {
+ var select = this.select_;
+ var selectedDestId = select.options[select.selectedIndex].value;
+
+ if (selectedDestId == DestinationSettings.MANAGE_ID_) {
+ cr.dispatchSimpleEvent(
+ this, DestinationSettings.EventType.MANAGE_PRINTERS_SELECT);
+ // Select first in the list.
+ this.destinationStore_.selectDestination(
+ this.destinationStore_.destinations[0]);
+ } else {
+ var destinations = this.destinationStore_.destinations;
+ for (var dest, i = 0; dest = destinations[i]; i++) {
+ if (dest.id == selectedDestId) {
+ this.destinationStore_.selectDestination(dest);
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ return {
+ DestinationSettings: DestinationSettings
+ };
+});
diff --git a/chrome/browser/resources/print_preview/settings/layout_settings.html b/chrome/browser/resources/print_preview/settings/layout_settings.html
new file mode 100644
index 0000000..3425e22b
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/layout_settings.html
@@ -0,0 +1,18 @@
+<div id="layout-settings" class="two-column visible layout-settings">
+ <h1 i18n-content="layoutLabel"></h1>
+ <div class="right-column">
+ <div class="radio"><label>
+ <input class="layout-settings-portrait-radio"
+ type="radio"
+ name="layout"
+ checked/>
+ <span i18n-content="optionPortrait"></span>
+ </label></div>
+ <div class="radio"><label>
+ <input class="layout-settings-landscape-radio"
+ type="radio"
+ name="layout"/>
+ <span i18n-content="optionLandscape"></span>
+ </label></div>
+ </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/settings/layout_settings.js b/chrome/browser/resources/print_preview/settings/layout_settings.js
new file mode 100644
index 0000000..cba29bf
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/layout_settings.js
@@ -0,0 +1,124 @@
+// 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 LayoutSettings object. This object encapsulates all settings and
+ * logic related to layout mode (portrait/landscape).
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
+ * layout written to the print ticket.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function LayoutSettings(printTicketStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to get the layout written to the print ticket.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+ };
+
+ /**
+ * CSS classes used by the layout settings.
+ * @enum {string}
+ * @private
+ */
+ LayoutSettings.Classes_ = {
+ LANDSCAPE_RADIO: 'layout-settings-landscape-radio',
+ PORTRAIT_RADIO: 'layout-settings-portrait-radio'
+ };
+
+ LayoutSettings.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ /** @param {boolean} isEnabled Whether this component is enabled. */
+ set isEnabled(isEnabled) {
+ this.landscapeRadioButton_.disabled = !isEnabled;
+ this.portraitRadioButton_.disabled = !isEnabled;
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.tracker.add(
+ this.portraitRadioButton_,
+ 'click',
+ this.onLayoutButtonClick_.bind(this));
+ this.tracker.add(
+ this.landscapeRadioButton_,
+ 'click',
+ this.onLayoutButtonClick_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.INITIALIZE,
+ this.onPrintTicketStoreChange_.bind(this));
+ },
+
+ /**
+ * @return {HTMLInputElement} The portrait orientation radio button.
+ * @private
+ */
+ get portraitRadioButton_() {
+ return this.getElement().getElementsByClassName(
+ LayoutSettings.Classes_.PORTRAIT_RADIO)[0];
+ },
+
+ /**
+ * @return {HTMLInputElement} The landscape orientation radio button.
+ * @private
+ */
+ get landscapeRadioButton_() {
+ return this.getElement().getElementsByClassName(
+ LayoutSettings.Classes_.LANDSCAPE_RADIO)[0];
+ },
+
+ /**
+ * Called when one of the radio buttons is clicked. Updates the print ticket
+ * store.
+ * @private
+ */
+ onLayoutButtonClick_: function() {
+ this.printTicketStore_.updateOrientation(
+ this.landscapeRadioButton_.checked);
+ },
+
+ /**
+ * Called when the print ticket store changes state. Updates the state of
+ * the radio buttons and hides the setting if necessary.
+ * @private
+ */
+ onPrintTicketStoreChange_: function() {
+ if (this.printTicketStore_.hasOrientationCapability()) {
+ var isLandscapeEnabled = this.printTicketStore_.isLandscapeEnabled();
+ this.portraitRadioButton_.checked = !isLandscapeEnabled;
+ this.landscapeRadioButton_.checked = isLandscapeEnabled;
+ fadeInOption(this.getElement());
+ } else {
+ fadeOutOption(this.getElement());
+ }
+ }
+ };
+
+ // Export
+ return {
+ LayoutSettings: LayoutSettings
+ };
+});
diff --git a/chrome/browser/resources/print_preview/margin_settings.html b/chrome/browser/resources/print_preview/settings/margin_settings.html
index 80d98d87..b3faaa3 100644
--- a/chrome/browser/resources/print_preview/margin_settings.html
+++ b/chrome/browser/resources/print_preview/settings/margin_settings.html
@@ -1,7 +1,9 @@
-<div id="margins-option" class="two-column visible">
+<div id="margin-settings" class="two-column visible margin-settings">
<h1 i18n-content="marginsLabel"></h1>
<div class="right-column">
- <select id="margin-list">
+ <select class="margin-settings-select">
+ <!-- The order of these options must match the natural order of their
+ values, which come from print_preview.ticket_items.MarginsType.Value. -->
<option i18n-content="defaultMargins" value="0" selected></option>
<option i18n-content="noMargins" value="1"></option>
<option i18n-content="minimumMargins" value="2"></option>
diff --git a/chrome/browser/resources/print_preview/settings/margin_settings.js b/chrome/browser/resources/print_preview/settings/margin_settings.js
new file mode 100644
index 0000000..54e5699
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/margin_settings.js
@@ -0,0 +1,112 @@
+// 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 MarginSettings object. This object encapsulates all settings and
+ * logic related to the margins mode.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to get
+ * ticket margins value.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function MarginSettings(printTicketStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to get ticket margins value.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+ };
+
+ /**
+ * CSS classes used by the margin settings component.
+ * @enum {string}
+ * @private
+ */
+ MarginSettings.Classes_ = {
+ SELECT: 'margin-settings-select'
+ };
+
+ MarginSettings.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ /** @param {boolean} isEnabled Whether this component is enabled. */
+ set isEnabled(isEnabled) {
+ this.select_.disabled = !isEnabled;
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.tracker.add(
+ this.select_, 'change', this.onSelectChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ },
+
+ /**
+ * @return {HTMLSelectElement} Select element containing the margin options.
+ * @private
+ */
+ get select_() {
+ return this.getElement().getElementsByClassName(
+ MarginSettings.Classes_.SELECT)[0];
+ },
+
+ /**
+ * Called when the select element is changed. Updates the print ticket
+ * margin type.
+ * @private
+ */
+ onSelectChange_: function() {
+ var select = this.select_;
+ var marginsType =
+ /** @type {print_preview.ticket_items.MarginsType.Value} */ (
+ select.selectedIndex);
+ this.printTicketStore_.updateMarginsType(marginsType);
+ },
+
+ /**
+ * Called when the print ticket store changes. Selects the corresponding
+ * select option.
+ * @private
+ */
+ onPrintTicketStoreChange_: function() {
+ if (this.printTicketStore_.hasMarginsCapability()) {
+ var select = this.select_;
+ var marginsType = this.printTicketStore_.getMarginsType();
+ var selectedMarginsType =
+ /** @type {print_preview.ticket_items.MarginsType.Value} */ (
+ select.selectedIndex);
+ if (marginsType != selectedMarginsType) {
+ select.options[selectedMarginsType].selected = false;
+ select.options[marginsType].selected = true;
+ }
+ fadeInOption(this.getElement());
+ } else {
+ fadeOutOption(this.getElement());
+ }
+ }
+ };
+
+ // Export
+ return {
+ MarginSettings: MarginSettings
+ };
+});
diff --git a/chrome/browser/resources/print_preview/settings/other_options_settings.html b/chrome/browser/resources/print_preview/settings/other_options_settings.html
new file mode 100644
index 0000000..623dfa0
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/other_options_settings.html
@@ -0,0 +1,20 @@
+<div id="other-options-settings"
+ class="other-options-settings two-column visible">
+ <h1 i18n-content="optionsLabel"></h1>
+ <div class="right-column checkbox">
+ <div class="other-options-settings-header-footer">
+ <label>
+ <input class="other-options-settings-header-footer-checkbox"
+ type="checkbox" />
+ <span i18n-content="optionHeaderFooter"></span>
+ </label>
+ </div>
+ <div class="other-options-settings-fit-to-page">
+ <label>
+ <input class="other-options-settings-fit-to-page-checkbox"
+ type="checkbox" />
+ <span i18n-content="optionFitToPage"></span>
+ </label>
+ </div>
+ </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/settings/other_options_settings.js b/chrome/browser/resources/print_preview/settings/other_options_settings.js
new file mode 100644
index 0000000..621b62b
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/other_options_settings.js
@@ -0,0 +1,172 @@
+// 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';
+
+ /**
+ * UI component that renders checkboxes for various print options.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to monitor
+ * the state of the print ticket.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function OtherOptionsSettings(printTicketStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to monitor the state of the print ticket.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+
+ /**
+ * Header footer container element.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.headerFooterEl_ = null;
+
+ /**
+ * Header footer checkbox.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.headerFooterCheckbox_ = null;
+
+ /**
+ * Fit-to-page container element.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.fitToPageEl_ = null;
+
+ /**
+ * Fit-to-page checkbox.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.fitToPageCheckbox_ = null;
+ };
+
+ /**
+ * CSS classes used by the other options component.
+ * @enum {string}
+ * @private
+ */
+ OtherOptionsSettings.Classes_ = {
+ FIT_TO_PAGE: 'other-options-settings-fit-to-page',
+ FIT_TO_PAGE_CHECKBOX: 'other-options-settings-fit-to-page-checkbox',
+ HEADER_FOOTER: 'other-options-settings-header-footer',
+ HEADER_FOOTER_CHECKBOX: 'other-options-settings-header-footer-checkbox'
+ };
+
+ OtherOptionsSettings.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ set isEnabled(isEnabled) {
+ this.headerFooterCheckbox_.disabled = !isEnabled;
+ this.fitToPageCheckbox_.disabled = !isEnabled;
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.tracker.add(
+ this.headerFooterCheckbox_,
+ 'click',
+ this.onHeaderFooterCheckboxClick_.bind(this));
+ this.tracker.add(
+ this.fitToPageCheckbox_,
+ 'click',
+ this.onFitToPageCheckboxClick_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.INITIALIZE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ },
+
+ /** @override */
+ exitDocument: function() {
+ print_preview.Component.prototype.exitDocument.call(this);
+ this.headerFooterEl_ = null;
+ this.headerFooterCheckbox_ = null;
+ this.fitToPageEl_ = null;
+ this.fitToPageCheckbox_ = null;
+ },
+
+ /** @override */
+ decorateInternal: function() {
+ this.headerFooterEl_ = this.getElement().getElementsByClassName(
+ OtherOptionsSettings.Classes_.HEADER_FOOTER)[0];
+ this.headerFooterCheckbox_ = this.getElement().getElementsByClassName(
+ OtherOptionsSettings.Classes_.HEADER_FOOTER_CHECKBOX)[0];
+ this.fitToPageEl_ = this.getElement().getElementsByClassName(
+ OtherOptionsSettings.Classes_.FIT_TO_PAGE)[0];
+ this.fitToPageCheckbox_ = this.getElement().getElementsByClassName(
+ OtherOptionsSettings.Classes_.FIT_TO_PAGE_CHECKBOX)[0];
+ },
+
+ /**
+ * Called when the header-footer checkbox is clicked. Updates the print
+ * ticket.
+ * @private
+ */
+ onHeaderFooterCheckboxClick_: function() {
+ this.printTicketStore_.updateHeaderFooter(
+ this.headerFooterCheckbox_.checked);
+ },
+
+ /**
+ * Called when the fit-to-page checkbox is clicked. Updates the print
+ * ticket.
+ * @private
+ */
+ onFitToPageCheckboxClick_: function() {
+ this.printTicketStore_.updateFitToPage(
+ this.fitToPageCheckbox_.checked);
+ },
+
+ /**
+ * Called when the print ticket store has changed. Hides or shows the
+ * setting.
+ * @private
+ */
+ onPrintTicketStoreChange_: function() {
+ setIsVisible(this.headerFooterEl_,
+ this.printTicketStore_.hasHeaderFooterCapability());
+ this.headerFooterCheckbox_.checked =
+ this.printTicketStore_.isHeaderFooterEnabled();
+ setIsVisible(this.fitToPageEl_,
+ this.printTicketStore_.hasFitToPageCapability());
+ this.fitToPageCheckbox_.checked =
+ this.printTicketStore_.isFitToPageEnabled();
+
+ if (this.printTicketStore_.hasHeaderFooterCapability() ||
+ this.printTicketStore_.hasFitToPageCapability()) {
+ fadeInOption(this.getElement());
+ } else {
+ fadeOutOption(this.getElement());
+ }
+ }
+ };
+
+ // Export
+ return {
+ OtherOptionsSettings: OtherOptionsSettings
+ };
+});
diff --git a/chrome/browser/resources/print_preview/settings/page_settings.css b/chrome/browser/resources/print_preview/settings/page_settings.css
new file mode 100644
index 0000000..cabdf7f
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/page_settings.css
@@ -0,0 +1,13 @@
+/* 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.
+ */
+
+#page-settings .page-settings-custom-input.invalid {
+ background: rgb(255, 240, 240);
+ color: rgb(140, 20, 20);
+}
+
+#page-settings .page-settings-print-pages-div {
+ white-space: nowrap;
+}
diff --git a/chrome/browser/resources/print_preview/settings/page_settings.html b/chrome/browser/resources/print_preview/settings/page_settings.html
new file mode 100644
index 0000000..76a8aef
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/page_settings.html
@@ -0,0 +1,23 @@
+<div id="page-settings" class="two-column visible page-settings">
+ <h1 i18n-content="pagesLabel"></h1>
+ <div class="right-column">
+ <div class="radio"><label>
+ <input class="page-settings-all-radio" name="pages" checked type="radio">
+ <span i18n-content="optionAllPages"></span>
+ </label></div>
+ <div>
+ <div class="page-settings-print-pages-div">
+ <input class="page-settings-custom-radio"
+ name="pages"
+ type="radio"
+ i18n-values="aria-label:printPagesLabel;"/>
+ <input class="page-settings-custom-input"
+ type="text"
+ i18n-values="placeholder:examplePageRangeText"/>
+ </div>
+ <span class="page-settings-custom-hint hint suggestion"
+ aria-hidden="true"
+ aria-live="polite"></span>
+ </div>
+ </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/settings/page_settings.js b/chrome/browser/resources/print_preview/settings/page_settings.js
new file mode 100644
index 0000000..1489c6b
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/page_settings.js
@@ -0,0 +1,247 @@
+// 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 PageSettings object. This object encapsulates all settings and
+ * logic related to page selection.
+ * @param {!print_preview.PrintTicketStore} printTicketStore Used to read and
+ * write page range settings.
+ * @constructor
+ * @extends {print_preview.Component}
+ */
+ function PageSettings(printTicketStore) {
+ print_preview.Component.call(this);
+
+ /**
+ * Used to read and write page range settings.
+ * @type {!print_preview.PrintTicketStore}
+ * @private
+ */
+ this.printTicketStore_ = printTicketStore;
+
+ /**
+ * Timeout used to delay processing of the custom page range input.
+ * @type {Object}
+ * @private
+ */
+ this.customInputTimeout_ = null;
+
+ /**
+ * Custom page range input.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.customInput_ = null;
+
+ /**
+ * Custom page range radio button.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.customRadio_ = null;
+
+ /**
+ * All page rage radio button.
+ * @type {HTMLInputElement}
+ * @private
+ */
+ this.allRadio_ = null;
+
+ /**
+ * Container of a hint to show when the custom page range is invalid.
+ * @type {HTMLElement}
+ * @private
+ */
+ this.customHintEl_ = null;
+ };
+
+ /**
+ * CSS classes used by the page settings.
+ * @enum {string}
+ * @private
+ */
+ PageSettings.Classes_ = {
+ ALL_RADIO: 'page-settings-all-radio',
+ CUSTOM_HINT: 'page-settings-custom-hint',
+ CUSTOM_INPUT: 'page-settings-custom-input',
+ CUSTOM_RADIO: 'page-settings-custom-radio'
+ };
+
+ /**
+ * Delay in milliseconds before processing custom page range input.
+ * @type {number}
+ * @private
+ */
+ PageSettings.CUSTOM_INPUT_DELAY_ = 500;
+
+ PageSettings.prototype = {
+ __proto__: print_preview.Component.prototype,
+
+ set isEnabled(isEnabled) {
+ this.customInput_.disabled = !isEnabled;
+ this.allRadio_.disabled = !isEnabled;
+ this.customRadio_.disabled = !isEnabled;
+ },
+
+ /** @override */
+ enterDocument: function() {
+ print_preview.Component.prototype.enterDocument.call(this);
+ this.tracker.add(
+ this.allRadio_, 'click', this.onAllRadioClick_.bind(this));
+ this.tracker.add(
+ this.customRadio_, 'click', this.onCustomRadioClick_.bind(this));
+ this.tracker.add(
+ this.customInput_, 'blur', this.onCustomInputBlur_.bind(this));
+ this.tracker.add(
+ this.customInput_, 'keyup', this.onCustomInputKeyUp_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.DOCUMENT_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.TICKET_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ this.tracker.add(
+ this.printTicketStore_,
+ print_preview.PrintTicketStore.EventType.CAPABILITIES_CHANGE,
+ this.onPrintTicketStoreChange_.bind(this));
+ },
+
+ /** @override */
+ exitDocument: function() {
+ print_preview.Component.prototype.exitDocument.call(this);
+ this.customInput_ = null;
+ this.customRadio_ = null;
+ this.allRadio_ = null;
+ this.customHintEl_ = null;
+ },
+
+ /** @override */
+ decorateInternal: function() {
+ this.customInput_ = this.getElement().getElementsByClassName(
+ PageSettings.Classes_.CUSTOM_INPUT)[0];
+ this.allRadio_ = this.getElement().getElementsByClassName(
+ PageSettings.Classes_.ALL_RADIO)[0];
+ this.customRadio_ = this.getElement().getElementsByClassName(
+ PageSettings.Classes_.CUSTOM_RADIO)[0];
+ this.customHintEl_ = this.getElement().getElementsByClassName(
+ PageSettings.Classes_.CUSTOM_HINT)[0];
+ this.customHintEl_.textContent = localStrings.getStringF(
+ 'pageRangeInstruction',
+ localStrings.getString('examplePageRangeText'));
+ },
+
+ /**
+ * @param {boolean} Whether the custom hint is visible.
+ * @private
+ */
+ setInvalidStateVisible_: function(isVisible) {
+ if (isVisible) {
+ this.customInput_.classList.add('invalid');
+ this.customHintEl_.setAttribute('aria-hidden', 'false');
+ fadeInElement(this.customHintEl_);
+ } else {
+ this.customInput_.classList.remove('invalid');
+ fadeOutElement(this.customHintEl_);
+ this.customHintEl_.setAttribute('aria-hidden', 'true');
+ }
+ },
+
+ /**
+ * Called when the all radio button is clicked. Updates the print ticket.
+ * @private
+ */
+ onAllRadioClick_: function() {
+ this.printTicketStore_.updatePageRange('');
+ },
+
+ /**
+ * Called when the custom radio button is clicked. Updates the print ticket.
+ * @private
+ */
+ onCustomRadioClick_: function() {
+ this.customInput_.focus();
+ this.printTicketStore_.updatePageRange(this.customInput_.value);
+ },
+
+ /**
+ * Called when the custom input is blurred. Enables the all radio button if
+ * the custom input is empty.
+ * @private
+ */
+ onCustomInputBlur_: function() {
+ if (this.customInput_.value == '') {
+ this.allRadio_.checked = true;
+ this.customRadio_.checked = false;
+ }
+ },
+
+ /**
+ * Called when a key is pressed on the custom input.
+ * @param {Event} event Contains the key that was pressed.
+ * @private
+ */
+ onCustomInputKeyUp_: function(event) {
+ if (this.customInputTimeout_) {
+ clearTimeout(this.customInputTimeout_);
+ }
+ if (event.keyIdentifier == 'Enter') {
+ this.printTicketStore_.updatePageRange(this.customInput_.value);
+ } else {
+ this.allRadio_.checked = false;
+ this.customRadio_.checked = true;
+ this.customInputTimeout_ = setTimeout(
+ this.onCustomInputTimeout_.bind(this),
+ PageSettings.CUSTOM_INPUT_DELAY_);
+ }
+ },
+
+ /**
+ * Called after a delay following a key press in the custom input.
+ * @private
+ */
+ onCustomInputTimeout_: function() {
+ this.customInputTimeout_ = null;
+ if (this.customRadio_.checked) {
+ this.printTicketStore_.updatePageRange(this.customInput_.value);
+ }
+ },
+
+ /**
+ * Called when the print ticket changes. Updates the state of the component.
+ * @private
+ */
+ onPrintTicketStoreChange_: function() {
+ if (this.printTicketStore_.hasPageRangeCapability()) {
+ var pageRangeStr = this.printTicketStore_.getPageRangeStr();
+ if (pageRangeStr || this.customRadio_.checked) {
+ if (!document.hasFocus() ||
+ document.activeElement != this.customInput_) {
+ this.customInput_.value = pageRangeStr;
+ }
+ this.customRadio_.checked = true;
+ this.allRadio_.checked = false;
+ this.setInvalidStateVisible_(
+ !this.printTicketStore_.isPageRangeValid());
+ } else {
+ this.allRadio_.checked = true;
+ this.customRadio_.checked = false;
+ this.setInvalidStateVisible_(false);
+ }
+ fadeInOption(this.getElement());
+ } else {
+ fadeOutOption(this.getElement());
+ }
+ }
+ };
+
+ // Export
+ return {
+ PageSettings: PageSettings
+ };
+});