diff options
author | rltoscano@google.com <rltoscano@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-31 18:14:21 +0000 |
---|---|---|
committer | rltoscano@google.com <rltoscano@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-31 18:14:21 +0000 |
commit | 96ff0da6fa46a6b2a94937ed5c58d578ac670fdb (patch) | |
tree | ab80f128e4a831d5c9aee9381bccf90f7ffdcada /chrome/browser/resources/print_preview | |
parent | 8daec68f1b4acf5ecc760232daed383c0b0d81cf (diff) | |
download | chromium_src-96ff0da6fa46a6b2a94937ed5c58d578ac670fdb.zip chromium_src-96ff0da6fa46a6b2a94937ed5c58d578ac670fdb.tar.gz chromium_src-96ff0da6fa46a6b2a94937ed5c58d578ac670fdb.tar.bz2 |
Implements print-destination search widget which replaces the old select drop-down element.
BUG=114206
NOTRY=true
TEST=Use the print preview dialog to switch printers before printing. Also sign-in with a Google Account to gain access to Google Cloud Print Printers.
Review URL: https://chromiumcodereview.appspot.com/10450022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139820 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/resources/print_preview')
58 files changed, 2208 insertions, 637 deletions
diff --git a/chrome/browser/resources/print_preview/cloud_print_interface.js b/chrome/browser/resources/print_preview/cloud_print_interface.js index b7e7c7c..15cc31d 100644 --- a/chrome/browser/resources/print_preview/cloud_print_interface.js +++ b/chrome/browser/resources/print_preview/cloud_print_interface.js @@ -103,7 +103,7 @@ cr.define('cloudprint', function() { * @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. + * @return {!Object} Google Cloud Print print ticket. */ createPrintTicket: function(destination, printTicketStore) { assert(!destination.isLocal, @@ -247,14 +247,14 @@ cr.define('cloudprint', function() { onSearchDone_: function(result) { var printerListJson = result['printers'] || []; var printerList = []; - for (var printerJson, i = 0; printerJson = printerListJson[i]; i++) { + printerListJson.forEach(function(printerJson) { 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); diff --git a/chrome/browser/resources/print_preview/component.js b/chrome/browser/resources/print_preview/component.js index f51c3ae1..f18864b 100644 --- a/chrome/browser/resources/print_preview/component.js +++ b/chrome/browser/resources/print_preview/component.js @@ -73,20 +73,20 @@ cr.define('print_preview', function() { */ enterDocument: function() { this.isInDocument_ = true; - for (var child, i = 0; child = this.children_[i]; i++) { + this.children_.forEach(function(child) { if (!child.isInDocument && child.getElement()) { child.enterDocument(); } - } + }); }, /** Removes all event listeners. */ exitDocument: function() { - for (var child, i = 0; child = this.children_[i]; i++) { + this.children_.forEach(function(child) { if (child.isInDocument) { child.exitDocument(); } - } + }); this.tracker_.removeAll(); this.isInDocument_ = false; }, diff --git a/chrome/browser/resources/print_preview/data/cloud_capabilities.js b/chrome/browser/resources/print_preview/data/cloud_capabilities.js index 7bb107f..abab759 100644 --- a/chrome/browser/resources/print_preview/data/cloud_capabilities.js +++ b/chrome/browser/resources/print_preview/data/cloud_capabilities.js @@ -111,7 +111,7 @@ cr.define('print_preview', function() { /** * 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. + * @param {!print_preview.CloudCapability.Type} type Type of the capability. * @constructor */ function CloudCapability(id, type) { @@ -124,7 +124,7 @@ cr.define('print_preview', function() { /** * Type of the capability. - * @type {print_preview.CloudCapability.Type} + * @type {!print_preview.CloudCapability.Type} * @private */ this.type_ = type; @@ -145,7 +145,7 @@ cr.define('print_preview', function() { return this.id_; }, - /** @return {print_preview.CloudCapability.Type} Type of the capability. */ + /** @return {!print_preview.CloudCapability.Type} Type of the capability. */ get type() { return this.type_; } @@ -190,7 +190,7 @@ cr.define('print_preview', function() { /** * Mapping of capability formats to an identifier of the collate capability. - * @type {object<CloudCapabilities.Format, string>} + * @type {!Object.<!CloudCapabilities.Format, string>} */ CollateCapability.Id = {}; CollateCapability.Id[CloudCapabilities.Format.PPD] = 'Collate'; @@ -264,7 +264,7 @@ cr.define('print_preview', function() { /** * Mapping of capability formats to an identifier of the color capability. - * @type {object<CloudCapabilities.Format, string>} + * @type {!Object.<!CloudCapabilities.Format, string>} */ ColorCapability.Id = {}; ColorCapability.Id[CloudCapabilities.Format.HP] = 'ns1:Colors'; @@ -319,7 +319,7 @@ cr.define('print_preview', function() { /** * Mapping of capability formats to an identifier of the copies capability. - * @type {object<CloudCapabilities.Format, string>} + * @type {!Object.<!CloudCapabilities.Format, string>} */ CopiesCapability.Id = {}; CopiesCapability.Id[CloudCapabilities.Format.XPS] = @@ -362,7 +362,7 @@ cr.define('print_preview', function() { /** * Mapping of capability formats to an identifier of the duplex capability. - * @type {object<CloudCapabilities.Format, string>} + * @type {!Object.<!CloudCapabilities.Format, string>} */ DuplexCapability.Id = {}; DuplexCapability.Id[CloudCapabilities.Format.PPD] = 'Duplex'; diff --git a/chrome/browser/resources/print_preview/data/cloud_parsers.js b/chrome/browser/resources/print_preview/data/cloud_parsers.js index 965e881..ed6cb15 100644 --- a/chrome/browser/resources/print_preview/data/cloud_parsers.js +++ b/chrome/browser/resources/print_preview/data/cloud_parsers.js @@ -18,37 +18,61 @@ cr.define('cloudprint', function() { DISPLAY_NAME: 'displayName', FORMAT: 'capsFormat', ID: 'id', - TAGS: 'tags' + TAGS: 'tags', + TYPE: 'type' }; /** * Special tag that denotes whether the destination has been recently used. * @type {string} + * @const * @private */ CloudDestinationParser.RECENT_TAG_ = '^recent'; /** + * Special tag that denotes whether the destination is owned by the user. + * @type {string} + * @const + * @private + */ + CloudDestinationParser.OWNED_TAG_ = '^own'; + + /** + * Enumeration of cloud destination types that are supported by print preview. + * @enum {string} + * @private + */ + CloudDestinationParser.CloudType_ = { + ANDROID: 'ANDROID_CHROME_SNAPSHOT', + DOCS: 'DOCS', + IOS: 'IOS_CHROME_SNAPSHOT' + }; + + /** * 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 + * @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_.TYPE) || !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 tags = json[CloudDestinationParser.Field_.TAGS] || []; + var isRecent = arrayContains(tags, CloudDestinationParser.RECENT_TAG_); + var isOwned = arrayContains(tags, CloudDestinationParser.OWNED_TAG_); var cloudDest = new print_preview.Destination( json[CloudDestinationParser.Field_.ID], + CloudDestinationParser.parseType_( + json[CloudDestinationParser.Field_.TYPE]), json[CloudDestinationParser.Field_.DISPLAY_NAME], isRecent, - false /*isLocal*/, - json[CloudDestinationParser.Field_.TAGS] || []); + tags, + isOwned); if (json.hasOwnProperty(CloudDestinationParser.Field_.CAPABILITIES) && json.hasOwnProperty(CloudDestinationParser.Field_.FORMAT)) { cloudDest.capabilities = CloudCapabilitiesParser.parse( @@ -59,6 +83,24 @@ cr.define('cloudprint', function() { }; /** + * Parses the destination type. + * @param {string} typeStr Destination type given by the Google Cloud Print + * server. + * @return {!print_preview.Destination.Type} Destination type. + * @private + */ + CloudDestinationParser.parseType_ = function(typeStr) { + if (typeStr == CloudDestinationParser.CloudType_.ANDROID || + typeStr == CloudDestinationParser.CloudType_.IOS) { + return print_preview.Destination.Type.MOBILE; + } else if (typeStr == CloudDestinationParser.CloudType_.DOCS) { + return print_preview.Destination.Type.GOOGLE_PROMOTED; + } else { + return print_preview.Destination.Type.GOOGLE; + } + }; + + /** * Namespace which contains a method to parse a cloud destination's print * capabilities. */ @@ -81,7 +123,7 @@ cr.define('cloudprint', function() { * 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. + * @param {!Array.<!Object>} json Object representing the cloud capabilities. * @return {!print_preview.CloudCapabilities} Parsed print capabilities. */ CloudCapabilitiesParser.parse = function(capsFormat, json) { @@ -89,7 +131,7 @@ cr.define('cloudprint', function() { var duplexCapability = null; var copiesCapability = null; var collateCapability = null; - for (var cap, i = 0; cap = json[i]; i++) { + json.forEach(function(cap) { var capId = cap[CloudCapabilitiesParser.Field_.CAP_ID]; if (capId == print_preview.CollateCapability.Id[capsFormat]) { collateCapability = CloudCapabilitiesParser.parseCollate(capId, cap); @@ -100,7 +142,7 @@ cr.define('cloudprint', function() { } else if (capId == print_preview.DuplexCapability.Id[capsFormat]) { duplexCapability = CloudCapabilitiesParser.parseDuplex(capId, cap); } - } + }); return new print_preview.CloudCapabilities( collateCapability, colorCapability, copiesCapability, duplexCapability); }; @@ -108,7 +150,7 @@ cr.define('cloudprint', function() { /** * 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. + * @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. @@ -118,7 +160,7 @@ cr.define('cloudprint', function() { var collateOption = null; var noCollateOption = null; var isCollateDefault = false; - for (var option, i = 0; option = options[i]; i++) { + options.forEach(function(option) { var optionId = option[CloudCapabilitiesParser.Field_.OPTION_ID]; if (!collateOption && print_preview.CollateCapability.COLLATE_REGEX.test(optionId)) { @@ -128,7 +170,7 @@ cr.define('cloudprint', function() { print_preview.CollateCapability.NO_COLLATE_REGEX.test(optionId)) { noCollateOption = optionId; } - } + }); if (!collateOption || !noCollateOption) { return null; } @@ -139,7 +181,7 @@ cr.define('cloudprint', function() { /** * 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. + * @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. @@ -149,7 +191,7 @@ cr.define('cloudprint', function() { var colorOption = null; var bwOption = null; var isColorDefault = false; - for (var option, i = 0; option = options[i]; i++) { + options.forEach(function(option) { var optionId = option[CloudCapabilitiesParser.Field_.OPTION_ID]; if (!colorOption && print_preview.ColorCapability.COLOR_REGEX.test(optionId)) { @@ -159,7 +201,7 @@ cr.define('cloudprint', function() { print_preview.ColorCapability.BW_REGEX.test(optionId)) { bwOption = optionId; } - } + }); if (!colorOption || !bwOption) { return null; } @@ -170,7 +212,7 @@ cr.define('cloudprint', function() { /** * 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. + * @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. @@ -180,7 +222,7 @@ cr.define('cloudprint', function() { var simplexOption = null; var longEdgeOption = null; var isDuplexDefault = false; - for (var option, i = 0; option = options[i]; i++) { + options.forEach(function(option) { var optionId = option[CloudCapabilitiesParser.Field_.OPTION_ID]; if (!simplexOption && print_preview.DuplexCapability.SIMPLEX_REGEX.test(optionId)) { @@ -190,7 +232,7 @@ cr.define('cloudprint', function() { longEdgeOption = optionId; isDuplexDefault = !!option[CloudCapabilitiesParser.Field_.DEFAULT]; } - } + }); if (!simplexOption || !longEdgeOption) { return null; } diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js index 01a9491..b62d818 100644 --- a/chrome/browser/resources/print_preview/data/destination.js +++ b/chrome/browser/resources/print_preview/data/destination.js @@ -9,13 +9,15 @@ cr.define('print_preview', function() { * Print destination data object that holds data for both local and cloud * destinations. * @param {string} id ID of the destination. + * @param {!print_preview.Destination.Type} type Type 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. + * @param {boolean=} opt_isOwned Whether the destination is owned by the user. + * Only applies to cloud-based destinations. * @constructor */ - function Destination(id, displayName, isRecent, isLocal, opt_tags) { + function Destination(id, type, displayName, isRecent, opt_tags, opt_isOwned) { /** * ID of the destination. * @type {string} @@ -24,6 +26,13 @@ cr.define('print_preview', function() { this.id_ = id; /** + * Type of the destination. + * @type {!print_preview.Destination.Type} + * @private + */ + this.type_ = type; + + /** * Display name of the destination. * @type {string} * @private @@ -38,13 +47,6 @@ cr.define('print_preview', function() { 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 @@ -59,8 +61,15 @@ cr.define('print_preview', function() { this.capabilities_ = null; /** + * Whether the destination is owned by the user. + * @type {boolean} + * @private + */ + this.isOwned_ = opt_isOwned || false; + + /** * Cache of destination location fetched from tags. - * @type {string} + * @type {?string} * @private */ this.location_ = null; @@ -79,8 +88,18 @@ cr.define('print_preview', function() { */ Destination.GooglePromotedId = { DOCS: '__google__docs', - SAVE_AS_PDF: 'Save as PDF', - PRINT_WITH_CLOUD_PRINT: 'printWithCloudPrint' + FEDEX: '__google__fedex', + SAVE_AS_PDF: 'Save as PDF' + }; + + /** + * Enumeration of the types of destinations. + * @enum {string} + */ + Destination.Type = { + GOOGLE: 'google', + LOCAL: 'local', + MOBILE: 'mobile' }; Destination.prototype = { @@ -89,6 +108,11 @@ cr.define('print_preview', function() { return this.id_; }, + /** @return {!print_preview.Destination.Type} Type of the destination. */ + get type() { + return this.type_; + }, + /** @return {string} Display name of the destination. */ get displayName() { return this.displayName_; @@ -106,9 +130,17 @@ cr.define('print_preview', function() { this.isRecent_ = isRecent; }, + /** + * @return {boolean} Whether the user owns the destination. Only applies to + * cloud-based destinations. + */ + get isOwned() { + return this.isOwned_; + }, + /** @return {boolean} Whether the destination is local or cloud-based. */ get isLocal() { - return this.isLocal_; + return this.type_ == Destination.Type.LOCAL; }, /** @return {boolean} Whether the destination is promoted by Google. */ @@ -122,14 +154,6 @@ cr.define('print_preview', function() { }, /** - * @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. */ @@ -138,12 +162,10 @@ cr.define('print_preview', function() { 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); + Destination.LOCATION_TAG_PREFIX.length) || ''; + break; } } - if (this.location_ == null) { - this.location_ = ''; - } } return this.location_; }, diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js index 69f766a..6c8d52d 100644 --- a/chrome/browser/resources/print_preview/data/destination_store.js +++ b/chrome/browser/resources/print_preview/data/destination_store.js @@ -8,20 +8,36 @@ cr.define('print_preview', function() { /** * A data store that stores destinations and dispatches events when the data * store changes. + * @param {!print_preview.NativeLayer} nativeLayer Used to fetch local print + * destinations. * @constructor * @extends {cr.EventTarget} */ - function DestinationStore() { + function DestinationStore(nativeLayer) { cr.EventTarget.call(this); /** + * Used to fetch local print destinations. + * @type {!print_preview.NativeLayer} + * @private + */ + this.nativeLayer_ = nativeLayer; + + /** * Internal backing store for the data store. - * @type {!Array.<print_preview.Destination>} + * @type {!Array.<!print_preview.Destination>} * @private */ this.destinations_ = []; /** + * Cache used for constant lookup of printers. + * @type {object.<string, !print_preview.Destination>} + * @private + */ + this.destinationMap_ = {}; + + /** * Currently selected destination. * @type {print_preview.Destination} * @private @@ -44,6 +60,41 @@ cr.define('print_preview', function() { * @private */ this.isInAutoSelectMode_ = false; + + /** + * Event tracker used to track event listeners of the destination store. + * @type {!EventTracker} + * @private + */ + this.tracker_ = new EventTracker(); + + /** + * Used to fetch cloud-based print destinations. + * @type {print_preview.CloudPrintInterface} + * @private + */ + this.cloudPrintInterface_ = null; + + /** + * Whether the destination store has already loaded or is loading all cloud + * destinations. + * @type {boolean} + * @private + */ + this.hasLoadedAllCloudDestinations_ = false; + + /** + * ID of a timeout after the initial destination ID is set. If no inserted + * destination matches the initial destination ID after the specified + * timeout, the first destination in the store will be automatically + * selected. + * @type {?number} + * @private + */ + this.autoSelectTimeout_ = null; + + this.addEventListeners_(); + this.reset_(); }; /** @@ -53,7 +104,44 @@ cr.define('print_preview', function() { DestinationStore.EventType = { DESTINATIONS_INSERTED: 'print_preview.DestinationStore.DESTINATIONS_INSERTED', - DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT' + DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT', + SELECTED_DESTINATION_CAPABILITIES_READY: + 'print_preview.DestinationStore.SELECTED_DESTINATION_CAPABILITIES_READY' + }; + + /** + * Delay in milliseconds before the destination store ignores the initial + * destination ID and just selects any printer (since the initial destination + * was not found). + * @type {number} + * @const + * @private + */ + DestinationStore.AUTO_SELECT_TIMEOUT_ = 2000; + + /** + * Creates a local PDF print destination. + * @return {!print_preview.Destination} Created print destination. + * @private + */ + DestinationStore.createLocalPdfPrintDestination_ = function() { + var dest = new print_preview.Destination( + print_preview.Destination.GooglePromotedId.SAVE_AS_PDF, + print_preview.Destination.Type.LOCAL, + localStrings.getString('printToPDF'), + false /*isRecent*/); + 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; }; DestinationStore.prototype = { @@ -80,31 +168,68 @@ cr.define('print_preview', function() { * 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. + * @param {?string} ID of the destination that should be selected + * automatically when added to the store or {@code null} if the first + * destination that is inserted should be selected. */ setInitialDestinationId: function(initialDestinationId) { this.initialDestinationId_ = initialDestinationId; this.isInAutoSelectMode_ = true; - if (this.initialDestinationId_ == null && this.destinations_.length > 0) { + if (this.initialDestinationId_ == null) { + assert(this.destinations_.length > 0, + 'No destinations available to select'); 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; - } + } else { + var candidate = this.destinationMap_[this.initialDestinationId_]; + if (candidate != null) { + this.selectDestination(candidate); } } }, + /** + * Sets the destination store's Google Cloud Print interface. + * @param {!print_preview.CloudPrintInterface} cloudPrintInterface Interface + * to set. + */ + setCloudPrintInterface: function(cloudPrintInterface) { + this.cloudPrintInterface_ = cloudPrintInterface; + 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)); + }, + /** @param {!print_preview.Destination} Destination to select. */ selectDestination: function(destination) { this.selectedDestination_ = destination; this.selectedDestination_.isRecent = true; this.isInAutoSelectMode_ = false; + if (this.autoSelectTimeout_ != null) { + clearTimeout(this.autoSelectTimeout_); + this.autoSelectTimeout_ = null; + } cr.dispatchSimpleEvent( this, DestinationStore.EventType.DESTINATION_SELECT); + if (destination.capabilities == null) { + 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 { + cr.dispatchSimpleEvent( + this, + DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); + } }, /** @@ -115,16 +240,13 @@ cr.define('print_preview', function() { * insert. */ insertDestination: function(destination) { - this.destinations_.push(destination); - cr.dispatchSimpleEvent( - this, DestinationStore.EventType.DESTINATIONS_INSERTED); - if (this.isInAutoSelectMode_) { - if (this.initialDestinationId_ == null) { + if (this.insertDestination_(destination)) { + cr.dispatchSimpleEvent( + this, DestinationStore.EventType.DESTINATIONS_INSERTED); + if (this.isInAutoSelectMode_ && + (this.initialDestinationId_ == null || + destination.id == this.initialDestinationId_)) { this.selectDestination(destination); - } else { - if (destination.id == this.initialDestinationId_) { - this.selectDestination(destination); - } } } }, @@ -137,20 +259,25 @@ cr.define('print_preview', function() { * 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; - } + var insertedDestination = false; + var destinationToAutoSelect = null; + destinations.forEach(function(dest) { + if (this.insertDestination_(dest)) { + insertedDestination = true; + if (this.isInAutoSelectMode_ && + destinationToAutoSelect == null && + (this.initialDestinationId_ == null || + dest.id == this.initialDestinationId_)) { + destinationToAutoSelect = dest; } } + }, this); + if (insertedDestination) { + cr.dispatchSimpleEvent( + this, DestinationStore.EventType.DESTINATIONS_INSERTED); + } + if (destinationToAutoSelect != null) { + this.selectDestination(destinationToAutoSelect); } }, @@ -162,14 +289,8 @@ cr.define('print_preview', function() { * 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) { + var existingDestination = this.destinationMap_[destination.id]; + if (existingDestination != null) { existingDestination.capabilities = destination.capabilities; return existingDestination; } else { @@ -177,11 +298,163 @@ cr.define('print_preview', function() { } }, - /** Clears all print destinations. */ - clear: function() { + /** Initiates loading of local print destinations. */ + startLoadLocalDestinations: function() { + this.nativeLayer_.startGetLocalDestinations(); + }, + + /** Initiates loading of recent cloud destinations. */ + startLoadRecentCloudDestinations: function() { + if (this.cloudPrintInterface_ != null) { + this.cloudPrintInterface_.search(true /*isRecent*/); + } + }, + + /** Initiates loading of all cloud destinations. */ + startLoadAllCloudDestinations: function() { + if (this.cloudPrintInterface_ != null && + !this.hasLoadedAllCloudDestinations_) { + this.cloudPrintInterface_.search(false /*isRecent*/); + this.hasLoadedAllCloudDestinations_ = true; + } + }, + + /** + * Inserts a destination into the store without dispatching any events. + * @return {boolean} Whether the inserted destination was not already in the + * store. + * @private + */ + insertDestination_: function(destination) { + if (this.destinationMap_[destination.id] == null) { + this.destinations_.push(destination); + this.destinationMap_[destination.id] = destination; + return true; + } else { + return false; + } + }, + + /** + * Binds handlers to events. + * @private + */ + addEventListeners_: function() { + 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)); + }, + + /** + * Resets the state of the destination store to its initial state. + * @private + */ + reset_: function() { this.destinations_ = []; + this.destinationMap_ = {}; this.selectedDestination_ = null; + this.hasLoadedAllCloudDestinations_ = false; + this.insertDestination( + DestinationStore.createLocalPdfPrintDestination_()); + this.autoSelectTimeout_ = setTimeout( + this.onAutoSelectTimeoutExpired_.bind(this), + DestinationStore.AUTO_SELECT_TIMEOUT_); + }, + + /** + * Called when the local destinations have been got from the native layer. + * @param {cr.Event} Contains the local destinations. + * @private + */ + onLocalDestinationsSet_: function(event) { + var localDestinations = event.destinationInfos.map(function(destInfo) { + return print_preview.LocalDestinationParser.parse(destInfo); + }); + this.insertDestinations(localDestinations); + }, + + /** + * 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 event.settingsInfo + // parameter. + if (this.selectedDestination_ && this.selectedDestination_.isLocal) { + var capabilities = print_preview.LocalCapabilitiesParser.parse( + event.settingsInfo); + this.selectedDestination_.capabilities = capabilities; + cr.dispatchSimpleEvent( + this, + DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); + } + }, + + /** + * Called when the /search call completes. Adds the fetched printers to the + * destination store. + * @param {cr.Event} event Contains the fetched printers. + * @private + */ + onCloudPrintSearchDone_: function(event) { + this.insertDestinations(event.printers); + }, + + /** + * Called when /printer call completes. Updates the specified destination's + * print capabilities. + * @param {cr.Event} event Contains detailed information about the + * destination. + * @private + */ + onCloudPrintPrinterDone_: function(event) { + var dest = this.updateDestination(event.printer); + if (this.selectedDestination_ == dest) { + cr.dispatchSimpleEvent( + this, + DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); + } + }, + + /** + * Called from native layer after the user was requested to sign in, and did + * so successfully. + * @private + */ + onDestinationsReload_: function() { + this.reset_(); this.isInAutoSelectMode_ = true; + this.startLoadLocalDestinations(); + this.startLoadRecentCloudDestinations(); + this.startLoadAllCloudDestinations(); + }, + + /** + * Called when no destination was auto-selected after some timeout. Selects + * the first destination in store. + * @private + */ + onAutoSelectTimeoutExpired_: function() { + this.autoSelectTimeout_ = null; + assert(this.destinations_.length > 0, + 'No destinations were loaded before auto-select timeout expired'); + this.selectDestination(this.destinations_[0]); } }; diff --git a/chrome/browser/resources/print_preview/data/local_parsers.js b/chrome/browser/resources/print_preview/data/local_parsers.js index af58290..b54e5a2 100644 --- a/chrome/browser/resources/print_preview/data/local_parsers.js +++ b/chrome/browser/resources/print_preview/data/local_parsers.js @@ -10,16 +10,16 @@ cr.define('print_preview', function() { /** * Parses a local print destination. - * @param {object} destinationInfo Information describing a local print + * @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, + print_preview.Destination.Type.LOCAL, destinationInfo.printerName, - false /*isRecent*/, - true /*isLocal*/); + false /*isRecent*/); }; /** Namespace that contains a method to parse local print capabilities. */ @@ -27,7 +27,7 @@ cr.define('print_preview', function() { /** * Parses local print capabilities. - * @param {object} settingsInfo Object that describes local print + * @param {!Object} settingsInfo Object that describes local print * capabilities. * @return {!print_preview.ChromiumCapabilities} Parsed local print * capabilities. diff --git a/chrome/browser/resources/print_preview/data/margins.js b/chrome/browser/resources/print_preview/data/margins.js index cf6a6f8..18ed90a 100644 --- a/chrome/browser/resources/print_preview/data/margins.js +++ b/chrome/browser/resources/print_preview/data/margins.js @@ -16,9 +16,8 @@ cr.define('print_preview', function() { function Margins(top, right, bottom, left) { /** * Backing store for the margin values in points. - * @type {Object.< - * print_preview.ticket_items.CustomMargins.Orientation, - * number>} + * @type {!Object.< + * !print_preview.ticket_items.CustomMargins.Orientation, number>} * @private */ this.value_ = {}; @@ -33,8 +32,8 @@ cr.define('print_preview', function() { Margins.prototype = { /** - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation - * Specifies the margin value to get. + * @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) { @@ -42,8 +41,8 @@ cr.define('print_preview', function() { }, /** - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation - * Specifies the margin to set. + * @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. diff --git a/chrome/browser/resources/print_preview/data/measurement_system.js b/chrome/browser/resources/print_preview/data/measurement_system.js index ccee0d9a..85b7c58 100644 --- a/chrome/browser/resources/print_preview/data/measurement_system.js +++ b/chrome/browser/resources/print_preview/data/measurement_system.js @@ -10,8 +10,8 @@ cr.define('print_preview', function() { * 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. + * @param {!print_preview.MeasurementSystem.UnitType} unitType Measurement + * unit type of the system. * @constructor */ function MeasurementSystem(thousandsDelimeter, decimalDelimeter, unitType) { @@ -48,7 +48,7 @@ cr.define('print_preview', function() { /** * Maximum resolution of local unit values. - * @type {Object.<print_preview.MeasurementSystem.UnitType, number>} + * @type {!Object.<!print_preview.MeasurementSystem.UnitType, number>} * @private */ MeasurementSystem.Precision_ = {}; @@ -57,7 +57,7 @@ cr.define('print_preview', function() { /** * Maximum number of decimal places to keep for local unit. - * @type {Object.<print_preview.MeasurementSystem.UnitType, number>} + * @type {!Object.<!print_preview.MeasurementSystem.UnitType, number>} * @private */ MeasurementSystem.DecimalPlaces_ = {}; diff --git a/chrome/browser/resources/print_preview/data/print_ticket_store.js b/chrome/browser/resources/print_preview/data/print_ticket_store.js index e200798..7f3a917 100644 --- a/chrome/browser/resources/print_preview/data/print_ticket_store.js +++ b/chrome/browser/resources/print_preview/data/print_ticket_store.js @@ -69,7 +69,7 @@ cr.define('print_preview', function() { * @private */ this.collate_ = - new print_preview.ticket_items.Collate(this.capabilitiesHolder_); + new print_preview.ticket_items.Collate(this.capabilitiesHolder_); /** * Color ticket item. @@ -142,6 +142,15 @@ cr.define('print_preview', function() { */ this.fitToPage_ = new print_preview.ticket_items.FitToPage( this.documentInfo_, this.destinationStore_); + + /** + * Keeps track of event listeners for the print ticket store. + * @type {!EventTracker} + * @private + */ + this.tracker_ = new EventTracker(); + + this.addEventListeners_(); }; /** @@ -243,12 +252,12 @@ cr.define('print_preview', function() { * 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 + * @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 + * @param {!print_preview.MeasurementSystem.UnitType} unitType Type of unit * of the local measurement system. */ initialize: function( @@ -276,28 +285,6 @@ cr.define('print_preview', function() { } }, - /** - * 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(); @@ -469,8 +456,8 @@ cr.define('print_preview', function() { }, /** - * @return {print_preview.ticket_items.MarginsType.Value} Type of predefined - * margins. + * @return {!print_preview.ticket_items.MarginsType.Value} Type of + * predefined margins. */ getMarginsType: function() { return this.marginsType_.getValue(); @@ -509,8 +496,8 @@ cr.define('print_preview', function() { }, /** - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation - * Specifies the margin to get the maximum value for. + * @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) { @@ -533,8 +520,8 @@ cr.define('print_preview', function() { /** * Updates a single custom margin's value in points. - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation - * Specifies the margin to update. + * @param {!print_preview.ticket_items.CustomMargins.Orientation} + * orientation Specifies the margin to update. * @param {number} value Updated margin in points. */ updateCustomMargin: function(orientation, value) { @@ -619,6 +606,40 @@ cr.define('print_preview', function() { this.getMarginsType() != print_preview.ticket_items.MarginsType.Value.CUSTOM || this.isCustomMarginsValid()); + }, + + /** + * Adds event listeners for the print ticket store. + * @private + */ + addEventListeners_: function() { + this.tracker_.add( + this.destinationStore_, + print_preview.DestinationStore.EventType. + SELECTED_DESTINATION_CAPABILITIES_READY, + this.onSelectedDestinationCapabilitiesReady_.bind(this)); + }, + + /** + * Called when the capabilities of the selected destination are ready. + * @private + */ + onSelectedDestinationCapabilitiesReady_: function() { + var caps = this.destinationStore_.selectedDestination.capabilities; + 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); + } } }; 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 index 774e35b..a9a0f07 100644 --- a/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js +++ b/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js @@ -46,7 +46,7 @@ cr.define('print_preview.ticket_items', function() { /** * Mapping of a margin orientation to its opposite. - * @type {object.<CustomMargins.Orientation, CustomMargins.Orientation>} + * @type {!Object.<!CustomMargins.Orientation, !CustomMargins.Orientation>} * @private */ CustomMargins.OppositeOrientation_ = {}; @@ -90,8 +90,8 @@ cr.define('print_preview.ticket_items', function() { }, /** - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation - * Specifies the margin to get the maximum value for. + * @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) { @@ -117,8 +117,8 @@ cr.define('print_preview.ticket_items', function() { /** * 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 {!print_preview.ticket_items.CustomMargins.Orientation} + * orientation Specifies the margin to update. * @param {number} value Updated margin value in points. */ updateMargin: function(orientation, value) { @@ -143,8 +143,8 @@ cr.define('print_preview.ticket_items', function() { }, /** - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation - * Specifies which margin to get the maximum value of. + * @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. 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 index 1dffd20..4753797 100644 --- a/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js +++ b/chrome/browser/resources/print_preview/data/ticket_items/ticket_item.js @@ -38,7 +38,7 @@ cr.define('print_preview.ticket_items', function() { throw Error('Abstract method not overridden'); }, - /** @return {object} The value of the ticket item. */ + /** @return {!Object} The value of the ticket item. */ getValue: function() { if (this.isCapabilityAvailable()) { if (this.value_ == null) { @@ -64,13 +64,13 @@ cr.define('print_preview.ticket_items', function() { return this.wouldValueBeValid(this.value_); }, - /** @param {object} Value to set as the value of the ticket item. */ + /** @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 + * @return {!Object} Default value of the ticket item if no value was set by * the user. * @protected */ @@ -79,7 +79,7 @@ cr.define('print_preview.ticket_items', function() { }, /** - * @return {object} Default value of the ticket item if the capability is + * @return {!Object} Default value of the ticket item if the capability is * not available. * @protected */ diff --git a/chrome/browser/resources/print_preview/data/user_info.js b/chrome/browser/resources/print_preview/data/user_info.js new file mode 100644 index 0000000..dcab125 --- /dev/null +++ b/chrome/browser/resources/print_preview/data/user_info.js @@ -0,0 +1,92 @@ +// 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'; + + /** + * Repository which stores information about the user. Events are dispatched + * when the information changes. + * @constructor + * @extends {cr.EventTarget} + */ + function UserInfo() { + cr.EventTarget.call(this); + + /** + * Tracker used to keep track of event listeners. + * @type {!EventTracker} + * @private + */ + this.tracker_ = new EventTracker(); + + /** + * Google Cloud Print interface to listen to for events. Currently, through + * Google Cloud Print is how we determine the info of the logged in user. + * @type {cloudprint.CloudPrintInterface} + * @private + */ + this.cloudPrintInterface_ = null; + + /** + * Email address of the logged in user or {@code null} if no user is logged + * in. + * @type {?string} + * @private + */ + this.userEmail_ = null; + }; + + /** + * Enumeration of event types dispatched by the user info. + * @enum {string} + */ + UserInfo.EventType = { + EMIAL_CHANGE: 'print_preview.UserInfo.EMAIL_CHANGE' + }; + + UserInfo.prototype = { + __proto__: cr.EventTarget.prototype, + + /** + * @return {?string} Email address of the logged in user or {@code null} if + * no user is logged. + */ + getUserEmail: function() { + return this.userEmail_; + }, + + /** + * @param {!cloudprint.CloudPrintInterface} cloudPrintInterface Interface + * to Google Cloud Print that the print preview uses. + */ + setCloudPrintInterface: function(cloudPrintInterface) { + this.cloudPrintInterface_ = cloudPrintInterface; + this.tracker_.add( + this.cloudPrintInterface_, + cloudprint.CloudPrintInterface.EventType.SEARCH_DONE, + this.onCloudPrintSearchDone_.bind(this)); + }, + + /** Removes all event listeners. */ + removeEventListeners: function() { + this.tracker_.removeAll(); + }, + + /** + * Called when a Google Cloud Print printer search completes. Updates user + * information. + * @type {cr.Event} event Contains information about the logged in user. + * @private + */ + onCloudPrintSearchDone_: function(event) { + this.userEmail_ = event.email; + cr.dispatchSimpleEvent(this, UserInfo.EventType.EMAIL_CHANGE); + } + }; + + return { + UserInfo: UserInfo + }; +}); diff --git a/chrome/browser/resources/print_preview/images/classic_printer_32.png b/chrome/browser/resources/print_preview/images/classic_printer_32.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/classic_printer_32.png diff --git a/chrome/browser/resources/print_preview/images/cloud.png b/chrome/browser/resources/print_preview/images/cloud.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/cloud.png diff --git a/chrome/browser/resources/print_preview/images/cloud_printer_32.png b/chrome/browser/resources/print_preview/images/cloud_printer_32.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/cloud_printer_32.png diff --git a/chrome/browser/resources/print_preview/images/cloud_printer_shared_32.png b/chrome/browser/resources/print_preview/images/cloud_printer_shared_32.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/cloud_printer_shared_32.png diff --git a/chrome/browser/resources/print_preview/images/google_promoted_printer_32.png b/chrome/browser/resources/print_preview/images/google_promoted_printer_32.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/google_promoted_printer_32.png diff --git a/chrome/browser/resources/print_preview/images/mobile_32.png b/chrome/browser/resources/print_preview/images/mobile_32.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/mobile_32.png diff --git a/chrome/browser/resources/print_preview/images/mobile_shared_32.png b/chrome/browser/resources/print_preview/images/mobile_shared_32.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/mobile_shared_32.png diff --git a/chrome/browser/resources/print_preview/images/search.png b/chrome/browser/resources/print_preview/images/search.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/browser/resources/print_preview/images/search.png diff --git a/chrome/browser/resources/print_preview/native_layer.js b/chrome/browser/resources/print_preview/native_layer.js index 8acec69..522c339 100644 --- a/chrome/browser/resources/print_preview/native_layer.js +++ b/chrome/browser/resources/print_preview/native_layer.js @@ -232,7 +232,7 @@ cr.define('print_preview', function() { 'fitToPageEnabled': printTicketStore.isFitToPageEnabled() }; - if (!destination.isLocal && !destination.isPrintWithCloudPrint) { + if (!destination.isLocal) { // 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. @@ -300,17 +300,17 @@ cr.define('print_preview', function() { }, /** Navigates the user to the system printer settings interface. */ - startManageLocalPrinters: function() { + startManageLocalDestinations: function() { chrome.send('manageLocalPrinters'); }, /** Navigates the user to the Google Cloud Print management page. */ - startManageCloudPrinters: function() { + startManageCloudDestinations: function() { chrome.send('manageCloudPrinters'); }, /** - * @param {object} initialSettings Object containing all initial settings. + * @param {!Object} initialSettings Object containing all initial settings. */ onSetInitialSettings_: function(initialSettings) { // TODO(rltoscano): Use initialSettings['cloudPrintData'] to prepopulate @@ -562,11 +562,11 @@ cr.define('print_preview', function() { * 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 + * @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 + * @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. @@ -625,7 +625,7 @@ cr.define('print_preview', function() { /** * Initial margins type. - * @type {?print_preview.ticket_items.MarginsType.Value} + * @type {print_preview.ticket_items.MarginsType.Value} * @private */ this.marginsType_ = marginsType; @@ -678,7 +678,7 @@ cr.define('print_preview', function() { }, /** - * @return {print_preview.MeasurementSystem.UnitType} Unit type of local + * @return {!print_preview.MeasurementSystem.UnitType} Unit type of local * machine's measurement system. */ get unitType() { @@ -691,7 +691,7 @@ cr.define('print_preview', function() { }, /** - * @return {?print_preview.ticket_items.MarginsType.Value} Initial margins + * @return {print_preview.ticket_items.MarginsType.Value} Initial margins * type or {@code null} if not initially set. */ get marginsType() { diff --git a/chrome/browser/resources/print_preview/preview_generator.js b/chrome/browser/resources/print_preview/preview_generator.js index 4787dc4..b001489 100644 --- a/chrome/browser/resources/print_preview/preview_generator.js +++ b/chrome/browser/resources/print_preview/preview_generator.js @@ -85,7 +85,7 @@ cr.define('print_preview', function() { /** * Margins type used to generate the last preview. - * @type {print_preview.ticket_items.MarginsType.Value} + * @type {!print_preview.ticket_items.MarginsType.Value} * @private */ this.marginsType_ = print_preview.ticket_items.MarginsType.Value.DEFAULT; diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control.css b/chrome/browser/resources/print_preview/previewarea/margin_control.css index 38c5834..7eb6a1f 100644 --- a/chrome/browser/resources/print_preview/previewarea/margin_control.css +++ b/chrome/browser/resources/print_preview/previewarea/margin_control.css @@ -1,7 +1,6 @@ /* 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. - */ + * found in the LICENSE file. */ #preview-area .margin-control { -webkit-transition: opacity 150ms linear; diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control.html b/chrome/browser/resources/print_preview/previewarea/margin_control.html index 58bbdbab..77381b2 100644 --- a/chrome/browser/resources/print_preview/previewarea/margin_control.html +++ b/chrome/browser/resources/print_preview/previewarea/margin_control.html @@ -1,6 +1,4 @@ -<div id="margin-control-template" - class="margin-control invisible" - style="display: none;"> +<div id="margin-control-template" class="margin-control invisible" hidden> <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 index 476371a..3f3c78d 100644 --- a/chrome/browser/resources/print_preview/previewarea/margin_control.js +++ b/chrome/browser/resources/print_preview/previewarea/margin_control.js @@ -7,7 +7,7 @@ cr.define('print_preview', function() { /** * Draggable control for setting a page margin. - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation + * @param {!print_preview.ticket_items.CustomMargins.Orientation} orientation * Orientation of the margin control that determines where the margin * textbox will be placed. * @constructor @@ -18,7 +18,7 @@ cr.define('print_preview', function() { /** * Determines where the margin textbox will be placed. - * @type {print_preview.ticket_items.CustomMargins.Orientation} + * @type {!print_preview.ticket_items.CustomMargins.Orientation} * @private */ this.orientation_ = orientation; @@ -67,7 +67,7 @@ cr.define('print_preview', function() { /** * Processing timeout for the textbox. - * @type {Object} + * @type {?number} * @private */ this.textTimeout_ = null; @@ -140,9 +140,9 @@ cr.define('print_preview', function() { /** * Map from orientation to CSS class name. - * @type {object.< - * print_preview.ticket_items.CustomMargins.Orientation, - * MarginControl.Classes_>} + * @type {!Object.< + * !print_preview.ticket_items.CustomMargins.Orientation, + * !MarginControl.Classes_>} * @private */ MarginControl.OrientationToClass_ = {}; @@ -185,7 +185,7 @@ cr.define('print_preview', function() { }, /** - * @return {print_preview.ticket_items.CustomMargins.Orientation} + * @return {!print_preview.ticket_items.CustomMargins.Orientation} * Orientation of the margin control. */ getOrientation: function() { diff --git a/chrome/browser/resources/print_preview/previewarea/margin_control_container.css b/chrome/browser/resources/print_preview/previewarea/margin_control_container.css index bfb1935..70236e6 100644 --- a/chrome/browser/resources/print_preview/previewarea/margin_control_container.css +++ b/chrome/browser/resources/print_preview/previewarea/margin_control_container.css @@ -1,7 +1,6 @@ /* 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. - */ + * found in the LICENSE file. */ .margin-control-container-dragging-vertical { cursor: ns-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 index 1209da9..52fd782 100644 --- a/chrome/browser/resources/print_preview/previewarea/margin_control_container.js +++ b/chrome/browser/resources/print_preview/previewarea/margin_control_container.js @@ -31,8 +31,8 @@ cr.define('print_preview', function() { /** * Convenience array that contains all of the margin controls. - * @type {!Object< - * print_preview.ticket_items.CustomMargins.Orientation, + * @type {!Object.< + * !print_preview.ticket_items.CustomMargins.Orientation, * !print_preview.MarginControl>} * @private */ @@ -90,7 +90,7 @@ cr.define('print_preview', function() { }; /** - * @param {print_preview.ticket_items.CustomMargins.Orientation} orientation + * @param {!print_preview.ticket_items.CustomMargins.Orientation} orientation * Orientation value to test. * @return {boolean} Whether the given orientation is TOP or BOTTOM. * @private diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.css b/chrome/browser/resources/print_preview/previewarea/preview_area.css index 137f914..c80199a 100644 --- a/chrome/browser/resources/print_preview/previewarea/preview_area.css +++ b/chrome/browser/resources/print_preview/previewarea/preview_area.css @@ -1,7 +1,6 @@ /* 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. - */ + * found in the LICENSE file. */ #preview-area.preview-area { -webkit-box-flex: 1; diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.html b/chrome/browser/resources/print_preview/previewarea/preview_area.html index 39b9d81..4f59507 100644 --- a/chrome/browser/resources/print_preview/previewarea/preview_area.html +++ b/chrome/browser/resources/print_preview/previewarea/preview_area.html @@ -8,28 +8,26 @@ ><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 preview-area-message" hidden> <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> + hidden></div> </div> </div> <div class="preview-area-preview-failed-message preview-area-message" - i18n-content="previewFailed" - style="display: none;"></div> + i18n-content="previewFailed" hidden></div> - <div class="preview-area-print-failed preview-area-message" style="display: none;"> + <div class="preview-area-print-failed preview-area-message" hidden> <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> + hidden></div> </div> </div> diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chrome/browser/resources/print_preview/previewarea/preview_area.js index 1ede80a..7fc8ec02 100644 --- a/chrome/browser/resources/print_preview/previewarea/preview_area.js +++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js @@ -95,7 +95,7 @@ cr.define('print_preview', function() { /** * Timeout object used to display a loading message if the preview is taking * a long time to generate. - * @type {Object} + * @type {?number} * @private */ this.loadingTimeout_ = null; @@ -352,8 +352,8 @@ cr.define('print_preview', function() { /** * Shows a given message on the overlay. - * @param {print_preview.PreviewArea.MessageId_} messageId ID of the message - * to show. + * @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 diff --git a/chrome/browser/resources/print_preview/print_header.css b/chrome/browser/resources/print_preview/print_header.css index dca74d3a..5011412 100644 --- a/chrome/browser/resources/print_preview/print_header.css +++ b/chrome/browser/resources/print_preview/print_header.css @@ -1,7 +1,6 @@ /* 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. - */ + * found in the LICENSE file. */ .print-header { padding-bottom: 10px; diff --git a/chrome/browser/resources/print_preview/print_header.js b/chrome/browser/resources/print_preview/print_header.js index 2d93429..059fb05 100644 --- a/chrome/browser/resources/print_preview/print_header.js +++ b/chrome/browser/resources/print_preview/print_header.js @@ -213,7 +213,9 @@ cr.define('print_preview', function() { */ onDestinationSelect_: function() { if (this.destinationStore_.selectedDestination.id == - print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) { + print_preview.Destination.GooglePromotedId.SAVE_AS_PDF || + this.destinationStore_.selectedDestination.id == + print_preview.Destination.GooglePromotedId.DOCS) { this.printButton_.textContent = localStrings.getString('saveButton'); } else { this.printButton_.textContent = localStrings.getString('printButton'); diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css index 1c91d66..72d0ba4 100644 --- a/chrome/browser/resources/print_preview/print_preview.css +++ b/chrome/browser/resources/print_preview/print_preview.css @@ -83,6 +83,7 @@ header { border-bottom: 1px solid #dcdcdc; padding-bottom: 10px; padding-top: 10px; + vertical-align: top; } .two-column:not(.visible) select { diff --git a/chrome/browser/resources/print_preview/print_preview.html b/chrome/browser/resources/print_preview/print_preview.html index c3fd255..f1b283b 100644 --- a/chrome/browser/resources/print_preview/print_preview.html +++ b/chrome/browser/resources/print_preview/print_preview.html @@ -10,6 +10,7 @@ <link rel="stylesheet" href="../shared/css/chrome_shared.css"/> <link rel="stylesheet" href="../shared/css/throbber.css"/> <link rel="stylesheet" href="print_header.css"/> + <link rel="stylesheet" href="settings/destination_settings.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"/> @@ -17,13 +18,18 @@ <link rel="stylesheet" href="previewarea/margin_control.css"/> <link rel="stylesheet" href="../shared/css/overlay.css"/> + <link rel="stylesheet" href="search/destination_list.css"/> + <link rel="stylesheet" href="search/destination_list_item.css"/> + <link rel="stylesheet" href="search/destination_search.css"/> + <link rel="stylesheet" href="search/search_box.css"/> + + <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> @@ -44,33 +50,26 @@ </div> <div id="link-container"> <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> + <button id="cloud-print-dialog-link" class="link-button navbar-link" + hidden i18n-content="cloudPrintDialogOption"></button> + <button id="system-dialog-link" class="link-button navbar-link" + hidden i18n-content="systemDialogOption"></button> + <div id="dialog-throbber" hidden class="throbber"></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> + <button id="open-pdf-in-preview-link" class="link-button navbar-link" + hidden i18n-content="openPdfInPreviewOption"></button> + <div id="open-preview-app-throbber" hidden class="throbber"></div> </div> </div> </div> + <include src="search/destination_search.html"/> <include src="previewarea/preview_area.html"/> <!-- HTML Templates --> <include src="previewarea/margin_control.html"/> + <include src="search/destination_list.html"/> + <include src="search/destination_list_item.html"/> </body> </html> diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js index ed78cfc..1fa15a3 100644 --- a/chrome/browser/resources/print_preview/print_preview.js +++ b/chrome/browser/resources/print_preview/print_preview.js @@ -2,16 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// 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. - // TODO(rltoscano): Move data/* into print_preview.data namespace -// TODO(rltoscano): Handle case where cloud print is initial destination, but -// cloud print is not enabled. - -var localStrings = new LocalStrings(); +var localStrings = new LocalStrings(templateData); <include src="component.js"/> @@ -34,11 +27,19 @@ cr.define('print_preview', function() { this.nativeLayer_ = new print_preview.NativeLayer(); /** + * Event target that contains information about the logged in user. + * @type {!print_preview.UserInfo} + * @private + */ + this.userInfo_ = new print_preview.UserInfo(); + + /** * Data store which holds print destinations. * @type {!print_preview.DestinationStore} * @private */ - this.destinationStore_ = new print_preview.DestinationStore(); + this.destinationStore_ = new print_preview.DestinationStore( + this.nativeLayer_); /** * Storage of the print ticket used to create the print job. @@ -58,6 +59,15 @@ cr.define('print_preview', function() { this.addChild(this.printHeader_); /** + * Component used to search for print destinations. + * @type {!print_preview.DestinationSearch} + * @private + */ + this.destinationSearch_ = new print_preview.DestinationSearch( + this.destinationStore_, this.userInfo_); + this.addChild(this.destinationSearch_); + + /** * Component that renders the print destination. * @type {!print_preview.DestinationSettings} * @private @@ -154,20 +164,11 @@ cr.define('print_preview', function() { 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)); }; /** @@ -186,36 +187,18 @@ cr.define('print_preview', function() { 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); + /** Sets up the page and print preview by getting the printer list. */ + initialize: function() { + this.decorate($('print-preview')); + i18nTemplate.process(document, templateData); + if (!this.previewArea_.hasCompatiblePlugin) { + this.setIsEnabled_(false); + } + this.nativeLayer_.startGetInitialSettings(); + this.destinationStore_.startLoadLocalDestinations(); }, /** @override */ @@ -231,18 +214,6 @@ cr.define('print_preview', function() { 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( @@ -294,8 +265,9 @@ cr.define('print_preview', function() { this.tracker.add( this.destinationStore_, - print_preview.DestinationStore.EventType.DESTINATION_SELECT, - this.onDestinationSelect_.bind(this)); + print_preview.DestinationStore.EventType. + SELECTED_DESTINATION_CAPABILITIES_READY, + this.printIfReady_.bind(this)); this.tracker.add( this.printHeader_, @@ -306,12 +278,43 @@ cr.define('print_preview', function() { print_preview.PrintHeader.EventType.CANCEL_BUTTON_CLICK, this.onCancelButtonClick_.bind(this)); + this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this)); + this.tracker.add( this.destinationSettings_, - print_preview.DestinationSettings.EventType.MANAGE_PRINTERS_SELECT, - this.onManagePrinters_.bind(this)); + print_preview.DestinationSettings.EventType.CHANGE_BUTTON_ACTIVATE, + this.onDestinationChangeButtonActivate_.bind(this)); - this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this)); + this.tracker.add( + this.destinationSearch_, + print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS, + this.onManageCloudDestinationsActivated_.bind(this)); + this.tracker.add( + this.destinationSearch_, + print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS, + this.onManageLocalDestinationsActivated_.bind(this)); + this.tracker.add( + this.destinationSearch_, + print_preview.DestinationSearch.EventType.SIGN_IN, + this.onCloudPrintSignInActivated_.bind(this)); + }, + + /** @override */ + decorateInternal: function() { + this.printHeader_.decorate($('print-header')); + this.destinationSearch_.decorate($('destination-search')); + 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); }, /** @@ -335,58 +338,6 @@ cr.define('print_preview', function() { }, /** - * 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 @@ -468,21 +419,6 @@ cr.define('print_preview', function() { }, /** - * 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. @@ -519,16 +455,8 @@ cr.define('print_preview', function() { * @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.cloudPrintInterface_ = + new cloudprint.CloudPrintInterface(event.baseCloudPrintUrl); this.tracker.add( this.cloudPrintInterface_, cloudprint.CloudPrintInterface.EventType.SUBMIT_DONE, @@ -538,75 +466,9 @@ cr.define('print_preview', function() { 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; + this.userInfo_.setCloudPrintInterface(this.cloudPrintInterface_); + this.destinationStore_.setCloudPrintInterface(this.cloudPrintInterface_); + this.destinationStore_.startLoadRecentCloudDestinations(); }, /** @@ -650,36 +512,6 @@ cr.define('print_preview', function() { }, /** - * 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 */ @@ -697,41 +529,11 @@ cr.define('print_preview', function() { * @private */ onCloudPrintError_: function(event) { - if (cr.isChromeOS && event.message == '403') { - this.nativeLayer_.startCloudPrintSignIn(); + if (event.message == '403') { + this.destinationSearch_.showCloudPrintPromo(); } 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_(); }, /** @@ -807,7 +609,11 @@ cr.define('print_preview', function() { // Escape key closes the dialog. if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) { - this.close_(); + if (this.destinationSearch_.getIsVisible()) { + this.destinationSearch_.setIsVisible(false); + } else { + this.close_(); + } e.preventDefault(); return; } @@ -837,25 +643,49 @@ cr.define('print_preview', function() { }, /** - * Called when the native layer dispatches a DISABLE_SCALING event. Updates - * the print ticket. + * Called when the destination settings' change button is activated. + * Displays the destination search component. * @private */ - onDisableScaling_: function() { - this.printTicketStore_.updateFitToPage(false); + onDestinationChangeButtonActivate_: function() { + this.destinationSearch_.setIsVisible(true); + this.destinationStore_.startLoadAllCloudDestinations(); }, /** - * Called when the user selects the "Manage printers..." option in the - * destination select. + * Called when the destination search dispatches manage cloud destinations + * event. Calls corresponding native layer method. * @private */ - onManagePrinters_: function() { - if (cr.isChromeOS) { - this.nativeLayer_.startManageCloudPrinters(); - } else { - this.nativeLayer_.startManageLocalPrinters(); - } + onManageCloudDestinationsActivated_: function() { + this.nativeLayer_.startManageCloudDestinations(); + }, + + /** + * Called when the destination search dispatches manage local destinations + * event. Calls corresponding native layer method. + * @private + */ + onManageLocalDestinationsActivated_: function() { + this.nativeLayer_.startManageLocalDestinations(); + }, + + /** + * Called when the user wants to sign in to Google Cloud Print. Calls the + * corresponding native layer event. + * @private + */ + onCloudPrintSignInActivated_: function() { + this.nativeLayer_.startCloudPrintSignIn(); + }, + + /** + * Called when the native layer dispatches a DISABLE_SCALING event. Updates + * the print ticket. + * @private + */ + onDisableScaling_: function() { + this.printTicketStore_.updateFitToPage(false); } }; @@ -881,6 +711,7 @@ cr.define('print_preview', function() { <include src="data/coordinate2d.js"/> <include src="data/size.js"/> <include src="data/capabilities_holder.js"/> +<include src="data/user_info.js"/> <include src="data/ticket_items/ticket_item.js"/> @@ -914,4 +745,13 @@ cr.define('print_preview', function() { <include src="previewarea/preview_area.js"/> <include src="preview_generator.js"/> -var printPreview = new print_preview.PrintPreview(); +<include src="search/destination_list.js"/> +<include src="search/cloud_destination_list.js"/> +<include src="search/destination_list_item.js"/> +<include src="search/destination_search.js"/> +<include src="search/search_box.js"/> + +window.addEventListener('DOMContentLoaded', function() { + printPreview = new print_preview.PrintPreview(); + printPreview.initialize(); +}); diff --git a/chrome/browser/resources/print_preview/print_preview_utils.js b/chrome/browser/resources/print_preview/print_preview_utils.js index 35bb80a..14eec32 100644 --- a/chrome/browser/resources/print_preview/print_preview_utils.js +++ b/chrome/browser/resources/print_preview/print_preview_utils.js @@ -192,12 +192,12 @@ function pageSetToPageRanges(pageSet) { * @param {boolean} isVisible Whether the element should be visible or not. */ function setIsVisible(element, isVisible) { - element.style.display = isVisible ? '' : 'none'; + element.hidden = !isVisible; } /** - * @param {Array.<object>} array Array to check for item. - * @param {object} item Item to look for in array. + * @param {!Array} array Array to check for item. + * @param {*} item Item to look for in array. * @return {boolean} Whether the item is in the array. */ function arrayContains(array, item) { diff --git a/chrome/browser/resources/print_preview/search/cloud_destination_list.js b/chrome/browser/resources/print_preview/search/cloud_destination_list.js new file mode 100644 index 0000000..a5b7c92 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/cloud_destination_list.js @@ -0,0 +1,50 @@ +// 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'; + + /** + * Sub-class of a destination list that shows cloud-based destinations. + * @param {!cr.EventTarget} eventTarget Event target to pass to destination + * items for dispatching SELECT events. + * @constructor + * @extends {print_preview.DestinationList} + */ + function CloudDestinationList(eventTarget) { + print_preview.DestinationList.call( + this, + eventTarget, + localStrings.getString('cloudDestinationsTitle'), + 0 /*opt_maxSize*/, + localStrings.getString('manage')); + }; + + CloudDestinationList.prototype = { + __proto__: print_preview.DestinationList.prototype, + + /** @override */ + updateDestinations: function(destinations) { + // Change the action link from "Manage..." to "Setup..." if user only has + // Docs and FedEx printers. + var docsId = print_preview.Destination.GooglePromotedId.DOCS; + var fedexId = print_preview.Destination.GooglePromotedId.FEDEX; + if ((destinations.length == 1 && destinations[0].id == docsId) || + (destinations.length == 2 && + ((destinations[0].id == docsId && destinations[1].id == fedexId) || + (destinations[0].id == fedexId && destinations[1].id == docsId)))) { + this.setActionLinkTextInternal( + localStrings.getString('setupCloudPrinters')); + } else { + this.setActionLinkTextInternal(localStrings.getString('manage')); + } + print_preview.DestinationList.prototype.updateDestinations.call( + this, destinations); + } + }; + + return { + CloudDestinationList: CloudDestinationList + }; +}); diff --git a/chrome/browser/resources/print_preview/search/destination_list.css b/chrome/browser/resources/print_preview/search/destination_list.css new file mode 100644 index 0000000..0490ff9 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_list.css @@ -0,0 +1,33 @@ +/* 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. */ + +.destination-list-header { + -webkit-padding-start: 0; + background-color: transparent; +} + +.destination-list-title { + -webkit-padding-end: 8px; + display: inline; +} + +.destination-list-destination-list-item-container { + -webkit-padding-start: 0; + list-style-type: none; + margin-bottom: 0; +} + +.destination-list-no-destinations-message { + -webkit-padding-start: 18px; + color: #999; +} + +.destination-list-footer { + -webkit-padding-start: 18px; + padding-top: 8px; +} + +.destination-list-total { + color: #999; +} diff --git a/chrome/browser/resources/print_preview/search/destination_list.html b/chrome/browser/resources/print_preview/search/destination_list.html new file mode 100644 index 0000000..47ae0ed --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_list.html @@ -0,0 +1,14 @@ +<div id="destination-list-template" hidden> + <header class="destination-list-header"> + <h4 class="destination-list-title"></h4> + <button class="destination-list-action-link link-button"></button> + </header> + <ul class="destination-list-destination-list-item-container"></ul> + <div class="destination-list-no-destinations-message" + i18n-content="noDestinationsMessage"></div> + <footer class="destination-list-footer" hidden> + <button class="destination-list-show-all-button" + i18n-content="showAllButtonText"></button> + <span class="destination-list-total"></span> + </footer> +</div> diff --git a/chrome/browser/resources/print_preview/search/destination_list.js b/chrome/browser/resources/print_preview/search/destination_list.js new file mode 100644 index 0000000..a64cc1e --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_list.js @@ -0,0 +1,319 @@ +// 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 displays a list of destinations with a heading, action link, + * and "Show All..." button. An event is dispatched when the action link is + * activated. + * @param {!cr.EventTarget} eventTarget Event target to pass to destination + * items for dispatching SELECT events. + * @param {string} title Title of the destination list. + * @param {number=} opt_maxSize Maximum size of the list. If not specified, + * defaults to no max. + * @param {string=} opt_actionLinkLabel Optional label of the action link. If + * no label is provided, the action link will not be shown. + * @constructor + * @extends {print_preview.Component} + */ + function DestinationList( + eventTarget, title, opt_maxSize, opt_actionLinkLabel) { + print_preview.Component.call(this); + + /** + * Event target to pass to destination items for dispatching SELECT events. + * @type {!cr.EventTarget} + * @private + */ + this.eventTarget_ = eventTarget; + + /** + * Title of the destination list. + * @type {string} + * @private + */ + this.title_ = title; + + /** + * Maximum size of the destination list. + * @type {number} + * @private + */ + this.maxSize_ = opt_maxSize || 0; + assert(this.maxSize_ <= DestinationList.SHORT_LIST_SIZE_, + 'Max size must be less than or equal to ' + + DestinationList.SHORT_LIST_SIZE_); + + /** + * Label of the action link. + * @type {?string} + * @private + */ + this.actionLinkLabel_ = opt_actionLinkLabel || null; + + /** + * Backing store for the destination list. + * @type {!Array.<print_preview.Destination>} + * @private + */ + this.destinations_ = []; + + /** + * Current query used for filtering. + * @type {?string} + * @private + */ + this.query_ = null; + + /** + * Whether the destination list is fully expanded. + * @type {boolean} + * @private + */ + this.isShowAll_ = false; + + /** + * Message to show when no destinations are available. + * @type {HTMLElement} + * @private + */ + this.noDestinationsMessageEl_ = null; + + /** + * Footer of the list. + * @type {HTMLElement} + * @private + */ + this.footerEl_ = null; + + /** + * Container for the destination list items. + * @type {HTMLElement} + * @private + */ + this.destinationListItemContainer_ = null; + }; + + /** + * Enumeration of event types dispatched by the destination list. + * @enum {string} + */ + DestinationList.EventType = { + // Dispatched when the action linked is activated. + ACTION_LINK_ACTIVATED: 'print_preview.DestinationList.ACTION_LINK_ACTIVATED' + }; + + /** + * Classes used by the destination list. + * @enum {string} + * @private + */ + DestinationList.Classes_ = { + ACTION_LINK: 'destination-list-action-link', + FOOTER: 'destination-list-footer', + NO_PRINTERS_MESSAGE: 'destination-list-no-destinations-message', + PRINTER_ITEM_CONTAINER: 'destination-list-destination-list-item-container', + SHOW_ALL_BUTTON: 'destination-list-show-all-button', + TITLE: 'destination-list-title', + TOTAL: 'destination-list-total' + }; + + /** + * Maximum number of destinations before showing the "Show All..." button. + * @type {number} + * @const + * @private + */ + DestinationList.SHORT_LIST_SIZE_ = 5; + + DestinationList.prototype = { + __proto__: print_preview.Component.prototype, + + /** @param {boolean} isShowAll Whether the show-all button is activated. */ + setIsShowAll: function(isShowAll) { + this.isShowAll_ = isShowAll; + this.renderDestinations_(); + }, + + /** @override */ + createDom: function() { + this.setElementInternal(this.cloneTemplateInternal( + 'destination-list-template')); + + var titleEl = this.getElement().getElementsByClassName( + DestinationList.Classes_.TITLE)[0]; + titleEl.textContent = this.title_; + + var actionLinkEl = this.getElement().getElementsByClassName( + DestinationList.Classes_.ACTION_LINK)[0]; + if (this.actionLinkLabel_) { + actionLinkEl.textContent = this.actionLinkLabel_; + } else { + setIsVisible(actionLinkEl, false); + } + + this.noDestinationsMessageEl_ = this.getElement().getElementsByClassName( + DestinationList.Classes_.NO_PRINTERS_MESSAGE)[0]; + this.footerEl_ = this.getElement().getElementsByClassName( + DestinationList.Classes_.FOOTER)[0]; + this.destinationListItemContainer_ = + this.getElement().getElementsByClassName( + DestinationList.Classes_.PRINTER_ITEM_CONTAINER)[0]; + }, + + /** @override */ + enterDocument: function() { + print_preview.Component.prototype.enterDocument.call(this); + var actionLinkEl = this.getElement().getElementsByClassName( + DestinationList.Classes_.ACTION_LINK)[0]; + var showAllButton = this.getElement().getElementsByClassName( + DestinationList.Classes_.SHOW_ALL_BUTTON)[0]; + this.tracker.add( + actionLinkEl, 'click', this.onActionLinkClick_.bind(this)); + this.tracker.add( + showAllButton, 'click', this.setIsShowAll.bind(this, true)); + }, + + /** @override */ + exitDocument: function() { + print_preview.Component.prototype.exitDocument.call(this); + this.noDestinationsMessageEl_ = null; + this.footerEl_ = null; + this.destinationListItemContainer_ = null; + }, + + /** + * Updates the destinations to render in the destination list. + * @param {!Array.<print_preview.Destination>} destinations Destinations to + * render. + */ + updateDestinations: function(destinations) { + this.destinations_ = destinations; + this.renderDestinations_(); + }, + + /** + * Filters the destination list with the given query. + * @param {?string} query Query to filter the list with. + */ + filter: function(query) { + this.query_ = query; + this.renderDestinations_(); + }, + + /** + * @param {string} text Text to set the action link to. + * @protected + */ + setActionLinkTextInternal: function(text) { + this.actionLinkLabel_ = text; + var actionLinkEl = this.getElement().getElementsByClassName( + DestinationList.Classes_.ACTION_LINK)[0]; + actionLinkEl.textContent = this.actionLinkLabel_; + }, + + /** + * Renders all destinations in the list that match the current query. For + * each render, all old destination items are first removed. + * @private + */ + renderDestinations_: function() { + this.removeChildren(); + + var filteredDests = []; + this.destinations_.forEach(function(destination) { + if (!this.query_ || destination.matches(this.query_)) { + filteredDests.push(destination); + } + }, this); + + // TODO(rltoscano): Sort filtered list? + + if (filteredDests.length == 0) { + this.renderEmptyList_(); + } else if (this.maxSize_) { + this.renderListWithMaxSize_(filteredDests); + } else { + this.renderListWithNoMaxSize_(filteredDests); + } + }, + + /** + * Renders a "No destinations found" element. + * @private + */ + renderEmptyList_: function() { + setIsVisible(this.noDestinationsMessageEl_, true); + setIsVisible(this.footerEl_, false); + }, + + /** + * Renders the list of destinations up to the maximum size. + * @param {!Array.<print_preview.Destination>} filteredDests Filtered list + * of print destinations to render. + * @private + */ + renderListWithMaxSize_: function(filteredDests) { + setIsVisible(this.noDestinationsMessageEl_, false); + setIsVisible(this.footerEl_, false); + for (var dest, i = 0; + i < this.maxSize_ && (dest = filteredDests[i]); + i++) { + var destListItem = new print_preview.DestinationListItem( + this.eventTarget_, dest); + this.addChild(destListItem); + destListItem.render(this.destinationListItemContainer_); + } + }, + + /** + * Renders all destinations in the given list. + * @param {!Array.<print_preview.Destination>} filteredDests Filtered list + * of print destinations to render. + * @private + */ + renderListWithNoMaxSize_: function(filteredDests) { + setIsVisible(this.noDestinationsMessageEl_, false); + if (filteredDests.length <= DestinationList.SHORT_LIST_SIZE_ || + this.isShowAll_) { + filteredDests.forEach(function(dest) { + var destListItem = new print_preview.DestinationListItem( + this.eventTarget_, dest); + this.addChild(destListItem); + destListItem.render(this.destinationListItemContainer_); + }, this); + setIsVisible(this.footerEl_, false); + } else { + for (var dest, i = 0; i < DestinationList.SHORT_LIST_SIZE_ - 1; i++) { + var destListItem = new print_preview.DestinationListItem( + this.eventTarget_, filteredDests[i]); + this.addChild(destListItem); + destListItem.render(this.destinationListItemContainer_); + } + setIsVisible(this.footerEl_, true); + var totalCountEl = this.getElement().getElementsByClassName( + DestinationList.Classes_.TOTAL)[0]; + totalCountEl.textContent = + localStrings.getStringF('destinationCount', filteredDests.length); + } + }, + + /** + * Called when the action link is clicked. Dispatches an + * ACTION_LINK_ACTIVATED event. + * @private + */ + onActionLinkClick_: function() { + cr.dispatchSimpleEvent( + this, DestinationList.EventType.ACTION_LINK_ACTIVATED); + } + }; + + // Export + return { + DestinationList: DestinationList + }; +}); diff --git a/chrome/browser/resources/print_preview/search/destination_list_item.css b/chrome/browser/resources/print_preview/search/destination_list_item.css new file mode 100644 index 0000000..25d2dc2 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_list_item.css @@ -0,0 +1,34 @@ +/* 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. */ + +.destination-list-item { + -webkit-padding-end: 2px; + -webkit-padding-start: 18px; + -webkit-transition: background-color 150ms; + cursor: default; + padding-bottom: 3px; + padding-top: 3px; +} + +.destination-list-item:hover { + background-color: rgb(228, 236, 247); +} + +.destination-list-item-icon { + -webkit-margin-end: 8px; + -webkit-transition: opacity 150ms; + display: inline-block; + height: 24px; + opacity: 0.4; + vertical-align: middle; + width: 24px; +} + +.destination-list-item:hover .destination-list-item-icon { + opacity: 1; +} + +.destination-list-item-name { + vertical-align: middle; +} diff --git a/chrome/browser/resources/print_preview/search/destination_list_item.html b/chrome/browser/resources/print_preview/search/destination_list_item.html new file mode 100644 index 0000000..972cda9 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_list_item.html @@ -0,0 +1,4 @@ +<li id="destination-list-item-template" class="destination-list-item" hidden> + <img class="destination-list-item-icon"/> + <span class="destination-list-item-name"></span> +</li> diff --git a/chrome/browser/resources/print_preview/search/destination_list_item.js b/chrome/browser/resources/print_preview/search/destination_list_item.js new file mode 100644 index 0000000..81adf91 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_list_item.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'; + + /** + * Component that renders a destination item in a destination list. + * @param {!cr.EventTarget} eventTarget Event target to dispatch selection + * events to. + * @param {!print_preview.Destination} destination Destination data object to + * render. + * @constructor + * @extends {print_preview.Component} + */ + function DestinationListItem(eventTarget, destination) { + print_preview.Component.call(this); + + /** + * Event target to dispatch selection events to. + * @type {!cr.EventTarget} + * @private + */ + this.eventTarget_ = eventTarget; + + /** + * Destination that the list item renders. + * @type {!print_preview.Destination} + * @private + */ + this.destination_ = destination; + }; + + /** + * Event types dispatched by the destination list item. + * @enum {string} + */ + DestinationListItem.EventType = { + // Dispatched when the list item is activated. + SELECT: 'print_preview.DestinationListItem.SELECT' + }; + + /** + * CSS classes used by the destination list item. + * @enum {string} + * @private + */ + DestinationListItem.Classes_ = { + ICON: 'destination-list-item-icon', + NAME: 'destination-list-item-name' + }; + + /** + * URLs of the various destination list item icons. + * @enum {string} + * @private + */ + DestinationListItem.Icons_ = { + CLOUD: 'images/cloud_printer_32.png', + CLOUD_SHARED: 'images/cloud_printer_shared_32.png', + LOCAL: 'images/classic_printer_32.png', + MOBILE: 'images/mobile_32.png', + MOBILE_SHARED: 'images/mobile_shared_32.png', + GOOGLE_PROMOTED: 'images/google_promoted_printer_32.png' + }, + + DestinationListItem.prototype = { + __proto__: print_preview.Component.prototype, + + /** @override */ + createDom: function() { + this.setElementInternal(this.cloneTemplateInternal( + 'destination-list-item-template')); + + var iconUrl; + if (this.destination_.isGooglePromoted) { + iconUrl = DestinationListItem.Icons_.GOOGLE_PROMOTED; + } else if (this.destination_.isLocal) { + iconUrl = DestinationListItem.Icons_.LOCAL; + } else if (this.destination_.type == + print_preview.Destination.Type.MOBILE && this.destination_.isOwned) { + iconUrl = DestinationListItem.Icons_.MOBILE; + } else if (this.destination_.type == + print_preview.Destination.Type.MOBILE && !this.destination_.isOwned) { + iconUrl = DestinationListItem.Icons_.MOBILE_SHARED; + } else if (this.destination_.type == + print_preview.Destination.Type.GOOGLE && this.destination_.isOwned) { + iconUrl = DestinationListItem.Icons_.CLOUD; + } else { + iconUrl = DestinationListItem.Icons_.CLOUD_SHARED; + } + + var iconImg = this.getElement().getElementsByClassName( + print_preview.DestinationListItem.Classes_.ICON)[0]; + iconImg.src = iconUrl; + var nameEl = this.getElement().getElementsByClassName( + DestinationListItem.Classes_.NAME)[0]; + nameEl.textContent = this.destination_.displayName; + }, + + /** @override */ + enterDocument: function() { + print_preview.Component.prototype.enterDocument.call(this); + this.tracker.add(this.getElement(), 'click', this.onActivate_.bind(this)); + }, + + /** + * Called when the destination item is activated. Dispatches a SELECT event + * on the given event target. + * @private + */ + onActivate_: function() { + var selectEvt = new cr.Event(DestinationListItem.EventType.SELECT); + selectEvt.destination = this.destination_; + this.eventTarget_.dispatchEvent(selectEvt); + } + }; + + // Export + return { + DestinationListItem: DestinationListItem + }; +}); diff --git a/chrome/browser/resources/print_preview/search/destination_search.css b/chrome/browser/resources/print_preview/search/destination_search.css new file mode 100644 index 0000000..2a93e68 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_search.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. */ + +.destination-search { + z-index: 3; +} + +.destination-search.transparent { + opacity: 0; + pointer-events: none; +} + +.destination-search-page { + height: 640px; + width: 700px; +} + +.destination-search-user-info { + -webkit-user-select: none; + position: absolute; + right: 80px; + top: 16px; + white-space: nowrap; +} + +[dir='rtl'] .destination-search-user-info { + left: 80px; + right: auto; +} + +.destination-search-search-box-container { + -webkit-user-select: none; + margin: 14px; +} + +.destination-search-lists { + -webkit-box-flex: 1; + overflow-y: auto; +} + +.destination-search-recent-list, +.destination-search-local-list, +.destination-search-cloud-list { + -webkit-user-select: none; + padding: 0 14px 18px; +} + +.destination-search-cloudprint-promo { + -webkit-padding-end: 44px; + -webkit-padding-start: 12px; + -webkit-user-select: none; + background-color: rgb(249, 237, 190); + padding-bottom: 12px; + padding-top: 12px; + position: relative; +} + +.destination-search-cloudprint-promo > * { + vertical-align: middle; +} + +.destination-search-sign-in.link-button { + padding: inherit; +} + +.destination-search-cloud-icon { + -webkit-margin-end: 4px; + display: inline-block; + height: 24px; + width: 24px; +} + +.destination-search-cloudprint-promo-close-button { + background-image: url(chrome://resources/images/x.png); + height: 24px; + margin-top: -9px; + position: absolute; + right: 10px; + top: 50%; + width: 24px; +} + +[dir='rtl'] .destination-search-cloudprint-promo-close-button { + left: 10px; + right: auto; +} + +.destination-search-cloudprint-promo-close-button:hover { + background-image: url(chrome://resources/images/x-hover.png); +} diff --git a/chrome/browser/resources/print_preview/search/destination_search.html b/chrome/browser/resources/print_preview/search/destination_search.html new file mode 100644 index 0000000..0d508ec --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_search.html @@ -0,0 +1,25 @@ +<div id="destination-search" + class="destination-search overlay transparent"> + <div class="destination-search-page page"> + <h1 class="destination-search-title" + i18n-content="destinationSearchTitle"></h1> + <span class="destination-search-user-info" hidden> + <span i18n-content="signedInAsPrefix"></span> + <span class="destination-search-user-email"></span> + </span> + <div class="destination-search-close-button close-button"></div> + <div class="destination-search-search-box-container"> + <include src="search_box.html"/> + </div> + <div class="destination-search-lists"> + <div class="destination-search-recent-list"></div> + <div class="destination-search-local-list"></div> + <div class="destination-search-cloud-list" hidden></div> + </div> + <div class="destination-search-cloudprint-promo" hidden> + <div class="destination-search-cloudprint-promo-close-button"></div> + <img src="../images/cloud.png" class="destination-search-cloud-icon"/> + <span class="destination-search-cloudprint-promo-text"></span> + </div> + </div> +</div> diff --git a/chrome/browser/resources/print_preview/search/destination_search.js b/chrome/browser/resources/print_preview/search/destination_search.js new file mode 100644 index 0000000..05c2cee --- /dev/null +++ b/chrome/browser/resources/print_preview/search/destination_search.js @@ -0,0 +1,433 @@ +// 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 used for searching for a print destination. + * This is a modal dialog that allows the user to search and select a + * destination to print to. When a destination is selected, it is written to + * the destination store. + * @param {!print_preview.DestinationStore} destinationStore Data store + * containing the destinations to search through. + * @param {!print_preview.UserInfo} userInfo Event target that contains + * information about the logged in user. + * @constructor + * @extends {print_preview.Component} + */ + function DestinationSearch(destinationStore, userInfo) { + print_preview.Component.call(this); + + /** + * Data store containing the destinations to search through. + * @type {!print_preview.DestinationStore} + * @private + */ + this.destinationStore_ = destinationStore; + + /** + * Event target that contains information about the logged in user. + * @type {!print_preview.UserInfo} + * @private + */ + this.userInfo_ = userInfo; + + /** + * Search box used to search through the destination lists. + * @type {!print_preview.SearchBox} + * @private + */ + this.searchBox_ = new print_preview.SearchBox(); + this.addChild(this.searchBox_); + + /** + * Destination list containing recent destinations. + * @type {!print_preview.DestinationList} + * @private + */ + this.recentList_ = new print_preview.DestinationList( + this, + localStrings.getString('recentDestinationsTitle'), + 3 /*opt_maxSize*/); + this.addChild(this.recentList_); + + /** + * Destination list containing local destinations. + * @type {!print_preview.DestinationList} + * @private + */ + this.localList_ = new print_preview.DestinationList( + this, + localStrings.getString('localDestinationsTitle'), + 0 /*opt_maxSize*/, + localStrings.getString('manage')); + this.addChild(this.localList_); + + /** + * Destination list containing cloud destinations. + * @type {!print_preview.DestinationList} + * @private + */ + this.cloudList_ = new print_preview.CloudDestinationList(this); + this.addChild(this.cloudList_); + + /** + * Page element of the overlay. + * @type {HTMLElement} + * @private + */ + this.pageEl_ = null; + }; + + /** + * Event types dispatched by the component. + * @enum {string} + */ + DestinationSearch.EventType = { + // Dispatched when the user requests to manage their cloud destinations. + MANAGE_CLOUD_DESTINATIONS: + 'print_preview.DestinationSearch.MANAGE_CLOUD_DESTINATIONS', + + // Dispatched when the user requests to manage their local destinations. + MANAGE_LOCAL_DESTINATIONS: + 'print_preview.DestinationSearch.MANAGE_LOCAL_DESTINATIONS', + + // Dispatched when the user requests to sign-in to their Google account. + SIGN_IN: 'print_preview.DestinationSearch.SIGN_IN' + }, + + /** + * CSS classes used by the component. + * @enum {string} + * @private + */ + DestinationSearch.Classes_ = { + CLOSE_BUTTON: 'destination-search-close-button', + CLOUDPRINT_PROMO: 'destination-search-cloudprint-promo', + CLOUDPRINT_PROMO_CLOSE_BUTTON: + 'destination-search-cloudprint-promo-close-button', + CLOUD_LIST: 'destination-search-cloud-list', + LOCAL_LIST: 'destination-search-local-list', + PAGE: 'destination-search-page', + PROMO_TEXT: 'destination-search-cloudprint-promo-text', + PULSE: 'pulse', + RECENT_LIST: 'destination-search-recent-list', + SEARCH_BOX_CONTAINER: 'destination-search-search-box-container', + SIGN_IN: 'destination-search-sign-in', + TRANSPARENT: 'transparent', + USER_EMAIL: 'destination-search-user-email', + USER_INFO: 'destination-search-user-info' + }; + + DestinationSearch.prototype = { + __proto__: print_preview.Component.prototype, + + /** @return {boolean} Whether the component is visible. */ + getIsVisible: function() { + return !this.getElement().classList.contains( + DestinationSearch.Classes_.TRANSPARENT); + }, + + /** @param {boolean} isVisible Whether the component is visible. */ + setIsVisible: function(isVisible) { + if (isVisible) { + this.searchBox_.focus(); + this.getElement().classList.remove( + DestinationSearch.Classes_.TRANSPARENT); + } else { + this.getElement().classList.add(DestinationSearch.Classes_.TRANSPARENT); + // Collapse all destination lists + this.localList_.setIsShowAll(false); + this.cloudList_.setIsShowAll(false); + this.searchBox_.setQuery(''); + this.filterLists_(null); + } + }, + + /** @param {string} email Email of the logged-in user. */ + setCloudPrintEmail: function(email) { + var userEmailEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.USER_EMAIL)[0]; + userEmailEl.textContent = email; + var userInfoEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.USER_INFO)[0]; + setIsVisible(userInfoEl, true); + var cloudListEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.CLOUD_LIST)[0]; + setIsVisible(cloudListEl, true); + var promoEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.CLOUDPRINT_PROMO)[0]; + setIsVisible(promoEl, false); + }, + + /** Shows the Google Cloud Print promotion banner. */ + showCloudPrintPromo: function() { + var promoEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.CLOUDPRINT_PROMO)[0]; + setIsVisible(promoEl, true); + }, + + /** @override */ + enterDocument: function() { + print_preview.Component.prototype.enterDocument.call(this); + var closeButtonEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.CLOSE_BUTTON)[0]; + var signInButton = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.SIGN_IN)[0]; + var cloudprintPromoCloseButton = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.CLOUDPRINT_PROMO_CLOSE_BUTTON)[0]; + + this.tracker.add( + closeButtonEl, 'click', this.onCloseClick_.bind(this)); + + var promoTextEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.PROMO_TEXT)[0]; + var signInEl = promoTextEl.getElementsByClassName( + DestinationSearch.Classes_.SIGN_IN)[0]; + this.tracker.add( + signInEl, 'click', this.onSignInActivated_.bind(this)); + + this.tracker.add( + cloudprintPromoCloseButton, + 'click', + this.onCloudprintPromoCloseButtonClick_.bind(this)); + this.tracker.add( + this.searchBox_, + print_preview.SearchBox.EventType.SEARCH, + this.onSearch_.bind(this)); + this.tracker.add( + this, + print_preview.DestinationListItem.EventType.SELECT, + this.onDestinationSelect_.bind(this)); + + this.tracker.add( + this.destinationStore_, + print_preview.DestinationStore.EventType.DESTINATIONS_INSERTED, + this.onDestinationsInserted_.bind(this)); + this.tracker.add( + this.destinationStore_, + print_preview.DestinationStore.EventType.DESTINATION_SELECT, + this.onDestinationStoreSelect_.bind(this)); + + this.tracker.add( + this.localList_, + print_preview.DestinationList.EventType.ACTION_LINK_ACTIVATED, + this.onManageLocalDestinationsActivated_.bind(this)); + this.tracker.add( + this.cloudList_, + print_preview.DestinationList.EventType.ACTION_LINK_ACTIVATED, + this.onManageCloudDestinationsActivated_.bind(this)); + + this.tracker.add( + this.getElement(), 'click', this.onClick_.bind(this)); + this.tracker.add( + this.pageEl_, 'webkitAnimationEnd', this.onAnimationEnd_.bind(this)); + + this.tracker.add( + this.userInfo_, + print_preview.UserInfo.EventType.EMAIL_CHANGE, + this.onEmailChange_.bind(this)); + }, + + /** @override */ + exitDocument: function() { + print_preview.Component.prototype.exitDocument.call(this); + this.pageEl_ = null; + }, + + /** @override */ + decorateInternal: function() { + this.searchBox_.decorate($('search-box')); + + var recentListEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.RECENT_LIST)[0]; + this.recentList_.render(recentListEl); + + var localListEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.LOCAL_LIST)[0]; + this.localList_.render(localListEl); + + var cloudListEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.CLOUD_LIST)[0]; + this.cloudList_.render(cloudListEl); + + this.pageEl_ = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.PAGE)[0]; + + var promoTextEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.PROMO_TEXT)[0]; + promoTextEl.innerHTML = localStrings.getStringF( + 'cloudPrintPromotion', + '<span class="destination-search-sign-in link-button">', + '</span>'); + }, + + /** + * Filters all destination lists with the given query. + * @param {?string} query Query to filter destination lists by. + * @private + */ + filterLists_: function(query) { + this.recentList_.filter(query); + this.localList_.filter(query); + this.cloudList_.filter(query); + }, + + /** + * Resets the search query. + * @private + */ + resetSearch_: function() { + this.searchBox_.setQuery(null); + this.filterLists_(null); + }, + + /** + * Called when a destination search should be executed. Filters the + * destination lists with the given query. + * @param {cr.Event} evt Contains the search query. + * @private + */ + onSearch_: function(evt) { + this.filterLists_(evt.query); + }, + + /** + * Called when the close button is clicked. Hides the search widget. + * @private + */ + onCloseClick_: function() { + this.setIsVisible(false); + this.resetSearch_(); + }, + + /** + * Called when a destination is selected. Clears the search and hides the + * widget. + * @param {cr.Event} evt Contains the selected destination. + * @private + */ + onDestinationSelect_: function(evt) { + this.setIsVisible(false); + this.resetSearch_(); + this.destinationStore_.selectDestination(evt.destination); + }, + + /** + * Called when destinations are added to the destination store. Refreshes UI + * with new destinations. + * @private + */ + onDestinationsInserted_: function() { + var recentDestinations = []; + var localDestinations = []; + var cloudDestinations = []; + this.destinationStore_.destinations.forEach(function(destination) { + if (destination.isRecent) { + recentDestinations.push(destination); + } + if (destination.isLocal) { + localDestinations.push(destination); + } else { + cloudDestinations.push(destination); + } + }); + this.recentList_.updateDestinations(recentDestinations); + this.localList_.updateDestinations(localDestinations); + this.cloudList_.updateDestinations(cloudDestinations); + }, + + /** + * Called when a destination is selected. Selected destination are marked as + * recent, so we have to update our recent destinations list. + * @private + */ + onDestinationStoreSelect_: function() { + var destinations = this.destinationStore_.destinations; + var recentDestinations = []; + destinations.forEach(function(destination) { + if (destination.isRecent) { + recentDestinations.push(destination); + } + }); + this.recentList_.updateDestinations(recentDestinations); + }, + + /** + * Called when the manage cloud printers action is activated. + * @private + */ + onManageCloudDestinationsActivated_: function() { + cr.dispatchSimpleEvent( + this, + print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS); + }, + + /** + * Called when the manage local printers action is activated. + * @private + */ + onManageLocalDestinationsActivated_: function() { + cr.dispatchSimpleEvent( + this, + print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS); + }, + + /** + * Called when the "Sign in" link on the Google Cloud Print promo is + * activated. + * @private + */ + onSignInActivated_: function() { + cr.dispatchSimpleEvent(this, DestinationSearch.EventType.SIGN_IN); + }, + + /** + * Called when the close button on the cloud print promo is clicked. Hides + * the promo. + * @private + */ + onCloudprintPromoCloseButtonClick_: function() { + var promoEl = this.getElement().getElementsByClassName( + DestinationSearch.Classes_.CLOUDPRINT_PROMO)[0]; + setIsVisible(promoEl, false); + }, + + /** + * Called when the overlay is clicked. Pulses the page. + * @param {Event} event Contains the element that was clicked. + * @private + */ + onClick_: function(event) { + if (event.target == this.getElement()) { + this.pageEl_.classList.add(DestinationSearch.Classes_.PULSE); + } + }, + + /** + * Called when an animation ends on the page. + * @private + */ + onAnimationEnd_: function() { + this.pageEl_.classList.remove(DestinationSearch.Classes_.PULSE); + }, + + /** + * Called when the user's email field has changed. Updates the UI. + * @private + */ + onEmailChange_: function() { + var userEmail = this.userInfo_.getUserEmail(); + if (userEmail) { + this.setCloudPrintEmail(userEmail); + } + } + }; + + // Export + return { + DestinationSearch: DestinationSearch + }; +}); diff --git a/chrome/browser/resources/print_preview/search/search_box.css b/chrome/browser/resources/print_preview/search/search_box.css new file mode 100644 index 0000000..bc282f7 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/search_box.css @@ -0,0 +1,24 @@ +/* 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. */ + +.search-box { + -webkit-user-select: none; + position: relative; +} + +.search-box-icon { + -webkit-user-select: none; + display: inline-block; + height: 12px; + left: 8px; + position: absolute; + right: 8px; + top: 6px; + width: 12px; +} + +.search-box-input { + text-indent: 24px; + width: 100%; +} diff --git a/chrome/browser/resources/print_preview/search/search_box.html b/chrome/browser/resources/print_preview/search/search_box.html new file mode 100644 index 0000000..cb4605a --- /dev/null +++ b/chrome/browser/resources/print_preview/search/search_box.html @@ -0,0 +1,5 @@ +<div id="search-box" class="search-box"> + <img src="../images/search.png" class="search-box-icon"/> + <input type="text" class="search-box-input" + i18n-values="placeholder:searchBoxPlaceholder"/> +</div> diff --git a/chrome/browser/resources/print_preview/search/search_box.js b/chrome/browser/resources/print_preview/search/search_box.js new file mode 100644 index 0000000..a0b9f30 --- /dev/null +++ b/chrome/browser/resources/print_preview/search/search_box.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'; + + /** + * Component that renders a search box for searching through destinations. + * @constructor + * @extends {print_preview.Component} + */ + function SearchBox() { + print_preview.Component.call(this); + + /** + * Timeout used to control incremental search. + * @type {?number} + * @private + */ + this.timeout_ = null; + + /** + * Input box where the query is entered. + * @type {HTMLInputElement} + * @private + */ + this.input_ = null; + }; + + /** + * Enumeration of event types dispatched from the search box. + * @enum {string} + */ + SearchBox.EventType = { + SEARCH: 'print_preview.SearchBox.SEARCH' + }; + + /** + * CSS classes used by the search box. + * @enum {string} + * @private + */ + SearchBox.Classes_ = { + INPUT: 'search-box-input' + }; + + /** + * Delay in milliseconds before dispatching a SEARCH event. + * @type {number} + * @const + * @private + */ + SearchBox.SEARCH_DELAY_ = 150; + + SearchBox.prototype = { + __proto__: print_preview.Component.prototype, + + /** @param {string} New query to set the search box's query to. */ + setQuery: function(query) { + query = query || ''; + this.input_.value = query.trim(); + }, + + /** Sets the input element of the search box in focus. */ + focus: function() { + this.input_.focus(); + }, + + /** @override */ + enterDocument: function() { + print_preview.Component.prototype.enterDocument.call(this); + this.tracker.add(this.input_, 'keydown', this.onInputKeyDown_.bind(this)); + }, + + /** @override */ + exitDocument: function() { + print_preview.Component.prototype.exitDocument.call(this); + this.input_ = null; + }, + + /** @override */ + decorateInternal: function() { + this.input_ = this.getElement().getElementsByClassName( + SearchBox.Classes_.INPUT)[0]; + }, + + /** + * @return {string} The current query of the search box. + * @private + */ + getQuery_: function() { + return this.input_.value.trim(); + }, + + /** + * Dispatches a SEARCH event. + * @private + */ + dispatchSearchEvent_: function() { + this.timeout_ = null; + var searchEvent = new cr.Event(SearchBox.EventType.SEARCH); + searchEvent.query = this.getQuery_(); + this.dispatchEvent(searchEvent); + }, + + /** + * Called when the input element's value changes. Dispatches a search event. + * @private + */ + onInputKeyDown_: function() { + if (this.timeout_) { + clearTimeout(this.timeout_); + } + this.timeout_ = setTimeout( + this.dispatchSearchEvent_.bind(this), SearchBox.SEARCH_DELAY_); + } + }; + + // Export + return { + SearchBox: SearchBox + }; +}); diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.css b/chrome/browser/resources/print_preview/settings/copies_settings.css index 129943f..a00ee9e9 100644 --- a/chrome/browser/resources/print_preview/settings/copies_settings.css +++ b/chrome/browser/resources/print_preview/settings/copies_settings.css @@ -1,7 +1,6 @@ /* 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. - */ + * found in the LICENSE file. */ #copies-settings .copies-settings-copies { position: relative; diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.js b/chrome/browser/resources/print_preview/settings/copies_settings.js index f2baecd..0f5f94cd 100644 --- a/chrome/browser/resources/print_preview/settings/copies_settings.js +++ b/chrome/browser/resources/print_preview/settings/copies_settings.js @@ -24,7 +24,7 @@ cr.define('print_preview', function() { /** * Timeout used to delay processing of the copies input. - * @type {Object} + * @type {?number} * @private */ this.textfieldTimeout_ = null; diff --git a/chrome/browser/resources/print_preview/settings/destination_settings.css b/chrome/browser/resources/print_preview/settings/destination_settings.css new file mode 100644 index 0000000..9d732d8 --- /dev/null +++ b/chrome/browser/resources/print_preview/settings/destination_settings.css @@ -0,0 +1,61 @@ +/* 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. */ + +.destination-settings-box { + display: -webkit-box; +} + +.destination-settings-icon { + -webkit-margin-end: 8px; + height: 32px; + opacity: 0.4; + width: 32px; +} + +.destination-settings-icon-local { + background-image: url(images/classic_printer_32.png); +} + +.destination-settings-icon-cloud { + background-image: url(images/cloud_printer_32.png); +} + +.destination-settings-icon-cloud-shared { + background-image: url(images/cloud_printer_shared_32.png); +} + +.destination-settings-icon-google-promoted { + background-image: url(images/google_promoted_printer_32.png); +} + +.destination-settings-icon-mobile { + background-image: url(images/mobile_32.png); +} + +.destination-settings-icon-mobile-shared { + background-image: url(images/mobile_shared_32.png); +} + +.destination-settings-info { + -webkit-box-flex: 1; + position: relative; + white-space: nowrap; +} + +.destination-settings-name { + font-size: 110%; + overflow: hidden; + position: absolute; + text-overflow: ellipsis; + width: 100%; +} + +.destination-settings-location { + color: gray; + overflow: hidden; + position: absolute; + text-overflow: ellipsis; + top: 1.5em; + width: 100%; +} diff --git a/chrome/browser/resources/print_preview/settings/destination_settings.html b/chrome/browser/resources/print_preview/settings/destination_settings.html index 55a9e47..9e65ad7 100644 --- a/chrome/browser/resources/print_preview/settings/destination_settings.html +++ b/chrome/browser/resources/print_preview/settings/destination_settings.html @@ -1,6 +1,14 @@ <div id="destination-settings" class="two-column visible"> <h1 i18n-content="destinationLabel"></h1> <div class="right-column"> - <select class="destination-settings-select"></select> + <div class="destination-settings-box"> + <div class="destination-settings-icon"></div> + <div class="destination-settings-info"> + <div class="destination-settings-name"></div> + <div class="destination-settings-location"></div> + </div> + </div> + <button class="destination-settings-change-button" + i18n-content="changeDestination"></button> </div> </div> diff --git a/chrome/browser/resources/print_preview/settings/destination_settings.js b/chrome/browser/resources/print_preview/settings/destination_settings.js index 4713d0a..e93fc2a 100644 --- a/chrome/browser/resources/print_preview/settings/destination_settings.js +++ b/chrome/browser/resources/print_preview/settings/destination_settings.js @@ -25,6 +25,13 @@ cr.define('print_preview', function() { * @private */ this.destinationStore_ = destinationStore; + + /** + * Current CSS class of the destination icon. + * @type {?DestinationSettings.Classes_} + * @private + */ + this.iconClass_ = null; }; /** @@ -32,8 +39,8 @@ cr.define('print_preview', function() { * @enum {string} */ DestinationSettings.EventType = { - MANAGE_PRINTERS_SELECT: - 'print_preview.DestinationSettings.MANAGE_PRINTERS_SELECT' + CHANGE_BUTTON_ACTIVATE: + 'print_preview.DestinationSettings.CHANGE_BUTTON_ACTIVATE' }; /** @@ -42,157 +49,91 @@ cr.define('print_preview', function() { * @private */ DestinationSettings.Classes_ = { - SELECT: 'destination-settings-select' + CHANGE_BUTTON: 'destination-settings-change-button', + ICON: 'destination-settings-icon', + ICON_CLOUD: 'destination-settings-icon-cloud', + ICON_CLOUD_SHARED: 'destination-settings-icon-cloud-shared', + ICON_GOOGLE_PROMOTED: 'destination-settings-icon-google-promoted', + ICON_LOCAL: 'destination-settings-icon-local', + ICON_MOBILE: 'destination-settings-icon-mobile', + ICON_MOBILE_SHARED: 'destination-settings-icon-mobile-shared', + LOCATION: 'destination-settings-location', + NAME: 'destination-settings-name' }; - /** - * Option value of the "Manage Printers..." select option. - * @type {string} - * @const - * @private - */ - DestinationSettings.MANAGE_ID_ = '__manage'; - DestinationSettings.prototype = { __proto__: print_preview.Component.prototype, + /** @param {boolean} Whether the component is enabled. */ set isEnabled(isEnabled) { - this.select_.disabled = !isEnabled; + var changeButton = this.getElement().getElementsByClassName( + DestinationSettings.Classes_.CHANGE_BUTTON)[0]; + changeButton.disabled = !isEnabled; }, /** @override */ enterDocument: function() { print_preview.Component.prototype.enterDocument.call(this); + var changeButton = this.getElement().getElementsByClassName( + DestinationSettings.Classes_.CHANGE_BUTTON)[0]; this.tracker.add( - this.select_, 'change', this.onSelectChange_.bind(this)); + changeButton, 'click', this.onChangeButtonClick_.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. + * Called when the "Change" button is clicked. Dispatches the + * CHANGE_BUTTON_ACTIVATE event. * @private */ - onDestinationsInserted_: function() { - this.renderDestinations_(); + onChangeButtonClick_: function() { + cr.dispatchSimpleEvent( + this, DestinationSettings.EventType.CHANGE_BUTTON_ACTIVATE); }, /** - * Called when the select element changes options. Selects the corresponding - * print destination. + * Called when the destination selection has changed. Updates UI elements. * @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]); + onDestinationSelect_: function() { + var destination = this.destinationStore_.selectedDestination; + var nameEl = this.getElement().getElementsByClassName( + DestinationSettings.Classes_.NAME)[0]; + nameEl.textContent = destination.displayName; + + var iconEl = this.getElement().getElementsByClassName( + DestinationSettings.Classes_.ICON)[0]; + if (this.iconClass_) { + iconEl.classList.remove(this.iconClass_); + } + if (destination.isGooglePromoted) { + this.iconClass_ = DestinationSettings.Classes_.ICON_GOOGLE_PROMOTED; + } else if (destination.isLocal) { + this.iconClass_ = DestinationSettings.Classes_.ICON_LOCAL; + } else if (destination.type == + print_preview.Destination.Type.MOBILE && destination.isOwned) { + this.iconClass_ = DestinationSettings.Classes_.ICON_MOBILE; + } else if (destination.type == + print_preview.Destination.Type.MOBILE && !destination.isOwned) { + this.iconClass_ = DestinationSettings.Classes_.ICON_MOBILE_SHARED; + } else if (destination.type == + print_preview.Destination.Type.GOOGLE && destination.isOwned) { + this.iconClass_ = DestinationSettings.Classes_.ICON_CLOUD; } else { - var destinations = this.destinationStore_.destinations; - for (var dest, i = 0; dest = destinations[i]; i++) { - if (dest.id == selectedDestId) { - this.destinationStore_.selectDestination(dest); - break; - } - } + this.iconClass_ = DestinationSettings.Classes_.ICON_CLOUD_SHARED; } + iconEl.classList.add(this.iconClass_); + + var locationEl = this.getElement().getElementsByClassName( + DestinationSettings.Classes_.LOCATION)[0]; + locationEl.textContent = destination.location; } }; + // Export return { DestinationSettings: DestinationSettings }; diff --git a/chrome/browser/resources/print_preview/settings/margin_settings.js b/chrome/browser/resources/print_preview/settings/margin_settings.js index 54e5699..290a733 100644 --- a/chrome/browser/resources/print_preview/settings/margin_settings.js +++ b/chrome/browser/resources/print_preview/settings/margin_settings.js @@ -77,7 +77,7 @@ cr.define('print_preview', function() { onSelectChange_: function() { var select = this.select_; var marginsType = - /** @type {print_preview.ticket_items.MarginsType.Value} */ ( + /** @type {!print_preview.ticket_items.MarginsType.Value} */ ( select.selectedIndex); this.printTicketStore_.updateMarginsType(marginsType); }, @@ -92,7 +92,7 @@ cr.define('print_preview', function() { var select = this.select_; var marginsType = this.printTicketStore_.getMarginsType(); var selectedMarginsType = - /** @type {print_preview.ticket_items.MarginsType.Value} */ ( + /** @type {!print_preview.ticket_items.MarginsType.Value} */ ( select.selectedIndex); if (marginsType != selectedMarginsType) { select.options[selectedMarginsType].selected = false; diff --git a/chrome/browser/resources/print_preview/settings/page_settings.css b/chrome/browser/resources/print_preview/settings/page_settings.css index cabdf7f..91f3ed4 100644 --- a/chrome/browser/resources/print_preview/settings/page_settings.css +++ b/chrome/browser/resources/print_preview/settings/page_settings.css @@ -1,7 +1,6 @@ /* 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. - */ + * found in the LICENSE file. */ #page-settings .page-settings-custom-input.invalid { background: rgb(255, 240, 240); diff --git a/chrome/browser/resources/print_preview/settings/page_settings.js b/chrome/browser/resources/print_preview/settings/page_settings.js index 1489c6b..95bd525 100644 --- a/chrome/browser/resources/print_preview/settings/page_settings.js +++ b/chrome/browser/resources/print_preview/settings/page_settings.js @@ -25,7 +25,7 @@ cr.define('print_preview', function() { /** * Timeout used to delay processing of the custom page range input. - * @type {Object} + * @type {?number} * @private */ this.customInputTimeout_ = null; |