diff options
Diffstat (limited to 'chromium/chrome/browser/resources/print_preview')
46 files changed, 734 insertions, 350 deletions
diff --git a/chromium/chrome/browser/resources/print_preview/OWNERS b/chromium/chrome/browser/resources/print_preview/OWNERS index b595d198396..193b90b2abf 100644 --- a/chromium/chrome/browser/resources/print_preview/OWNERS +++ b/chromium/chrome/browser/resources/print_preview/OWNERS @@ -1,4 +1,4 @@ -abodenha@chromium.org +alekseys@chromium.org dpapad@chromium.org gene@chromium.org kmadhusu@chromium.org diff --git a/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js b/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js index e918cda7d67..32ac59f93c9 100644 --- a/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js +++ b/chromium/chrome/browser/resources/print_preview/cloud_print_interface.js @@ -52,7 +52,7 @@ cr.define('cloudprint', function() { /** * Currently logged in users (identified by email) mapped to the Google * session index. - * @type {!Object.<string, number>} + * @type {!Object<string, number>} * @private */ this.userSessionIndex_ = {}; @@ -60,21 +60,21 @@ cr.define('cloudprint', function() { /** * Stores last received XSRF tokens for each user account. Sent as * a parameter with every request. - * @type {!Object.<string, string>} + * @type {!Object<string, string>} * @private */ this.xsrfTokens_ = {}; /** * Pending requests delayed until we get access token. - * @type {!Array.<!CloudPrintRequest>} + * @type {!Array<!CloudPrintRequest>} * @private */ this.requestQueue_ = []; /** * Outstanding cloud destination search requests. - * @type {!Array.<!CloudPrintRequest>} + * @type {!Array<!CloudPrintRequest>} * @private */ this.outstandingCloudSearchRequests_ = []; @@ -157,7 +157,7 @@ cr.define('cloudprint', function() { /** * Could Print origins used to search printers. - * @type {!Array.<!print_preview.Destination.Origin>} + * @type {!Array<!print_preview.Destination.Origin>} * @const * @private */ @@ -212,7 +212,7 @@ cr.define('cloudprint', function() { * @param {string} account Account the search is sent for. It matters for * COOKIES origin only, and can be empty (sent on behalf of the primary * user in this case). - * @param {!Array.<!print_preview.Destination.Origin>} origins Origins to + * @param {!Array<!print_preview.Destination.Origin>} origins Origins to * search printers for. * @private */ @@ -374,7 +374,7 @@ cr.define('cloudprint', function() { * Builds request to the Google Cloud Print API. * @param {string} method HTTP method of the request. * @param {string} action Google Cloud Print action to perform. - * @param {Array.<!HttpParam>} params HTTP parameters to include in the + * @param {Array<!HttpParam>} params HTTP parameters to include in the * request. * @param {!print_preview.Destination.Origin} origin Origin for destination. * @param {?string} account Account the request is sent for. Can be @@ -502,7 +502,7 @@ cr.define('cloudprint', function() { /** * Terminates search requests for requested {@code origins}. - * @param {!Array.<print_preview.Destination.Origin>} origins Origins + * @param {!Array<print_preview.Destination.Origin>} origins Origins * to terminate search requests for. * @private */ diff --git a/chromium/chrome/browser/resources/print_preview/component.js b/chromium/chrome/browser/resources/print_preview/component.js index 2238ab0119b..3c18829a22e 100644 --- a/chromium/chrome/browser/resources/print_preview/component.js +++ b/chromium/chrome/browser/resources/print_preview/component.js @@ -31,7 +31,7 @@ cr.define('print_preview', function() { /** * Child components of the component. - * @type {!Array.<!print_preview.Component>} + * @type {!Array<!print_preview.Component>} * @private */ this.children_ = []; @@ -119,7 +119,7 @@ cr.define('print_preview', function() { }, /** - * @return {!Array.<!print_preview.Component>} Child components of this + * @return {!Array<!print_preview.Component>} Child components of this * component. */ get children() { diff --git a/chromium/chrome/browser/resources/print_preview/data/app_state.js b/chromium/chrome/browser/resources/print_preview/data/app_state.js index a8ebb063211..a604e9d8e44 100644 --- a/chromium/chrome/browser/resources/print_preview/data/app_state.js +++ b/chromium/chrome/browser/resources/print_preview/data/app_state.js @@ -39,6 +39,8 @@ cr.define('print_preview', function() { SELECTED_DESTINATION_ORIGIN: 'selectedDestinationOrigin', SELECTED_DESTINATION_CAPABILITIES: 'selectedDestinationCapabilities', SELECTED_DESTINATION_NAME: 'selectedDestinationName', + SELECTED_DESTINATION_EXTENSION_ID: 'selectedDestinationExtensionId', + SELECTED_DESTINATION_EXTENSION_NAME: 'selectedDestinationExtensionName', IS_GCP_PROMO_DISMISSED: 'isGcpPromoDismissed', DPI: 'dpi', MEDIA_SIZE: 'mediaSize', @@ -82,7 +84,7 @@ cr.define('print_preview', function() { }, /** - * @return {?print_preview.Destination.Origin.<string>} Origin of the + * @return {?print_preview.Destination.Origin<string>} Origin of the * selected destination. */ get selectedDestinationOrigin() { @@ -99,6 +101,21 @@ cr.define('print_preview', function() { return this.state_[AppState.Field.SELECTED_DESTINATION_NAME]; }, + /** + * @return {?string} Extension ID associated with the selected destination. + */ + get selectedDestinationExtensionId() { + return this.state_[AppState.Field.SELECTED_DESTINATION_EXTENSION_ID]; + }, + + /** + * @return {?string} Extension name associated with the selected + * destination. + */ + get selectedDestinationExtensionName() { + return this.state_[AppState.Field.SELECTED_DESTINATION_EXTENSION_NAME]; + }, + /** @return {boolean} Whether the GCP promotion has been dismissed. */ get isGcpPromoDismissed() { return this.state_[AppState.Field.IS_GCP_PROMO_DISMISSED]; @@ -193,6 +210,10 @@ cr.define('print_preview', function() { this.state_[AppState.Field.SELECTED_DESTINATION_CAPABILITIES] = dest.capabilities; this.state_[AppState.Field.SELECTED_DESTINATION_NAME] = dest.displayName; + this.state_[AppState.Field.SELECTED_DESTINATION_EXTENSION_ID] = + dest.extensionId; + this.state_[AppState.Field.SELECTED_DESTINATION_EXTENSION_NAME] = + dest.extensionName; this.persist_(); }, diff --git a/chromium/chrome/browser/resources/print_preview/data/destination.js b/chromium/chrome/browser/resources/print_preview/data/destination.js index 4bbaeb12f28..edce220a5ee 100644 --- a/chromium/chrome/browser/resources/print_preview/data/destination.js +++ b/chromium/chrome/browser/resources/print_preview/data/destination.js @@ -11,10 +11,10 @@ cr.exportPath('print_preview'); * @typedef {{ * version: string, * printer: { - * vendor_capability: !Array.<{Object}>, + * vendor_capability: !Array<{Object}>, * collate: ({default: (boolean|undefined)}|undefined), * color: ({ - * option: !Array.<{ + * option: !Array<{ * type: (string|undefined), * vendor_id: (string|undefined), * custom_display_name: (string|undefined), @@ -23,10 +23,10 @@ cr.exportPath('print_preview'); * }|undefined), * copies: ({default: (number|undefined), * max: (number|undefined)}|undefined), - * duplex: ({option: !Array.<{type: (string|undefined), + * duplex: ({option: !Array<{type: (string|undefined), * is_default: (boolean|undefined)}>}|undefined), * page_orientation: ({ - * option: !Array.<{type: (string|undefined), + * option: !Array<{type: (string|undefined), * is_default: (boolean|undefined)}> * }|undefined) * } @@ -48,12 +48,14 @@ cr.define('print_preview', function() { * @param {boolean} isRecent Whether the destination has been used recently. * @param {!print_preview.Destination.ConnectionStatus} connectionStatus * Connection status of the print destination. - * @param {{tags: (Array.<string>|undefined), + * @param {{tags: (Array<string>|undefined), * isOwned: (boolean|undefined), * account: (string|undefined), * lastAccessTime: (number|undefined), * isTosAccepted: (boolean|undefined), * cloudID: (string|undefined), + * extensionId: (string|undefined), + * extensionName: (string|undefined), * description: (string|undefined)}=} opt_params Optional parameters * for the destination. * @constructor @@ -92,7 +94,7 @@ cr.define('print_preview', function() { /** * Tags associated with the destination. - * @private {!Array.<string>} + * @private {!Array<string>} */ this.tags_ = (opt_params && opt_params.tags) || []; @@ -153,11 +155,23 @@ cr.define('print_preview', function() { * @private {string} */ this.cloudID_ = (opt_params && opt_params.cloudID) || ''; + + /** + * Extension ID for extension managed printers. + * @private {string} + */ + this.extensionId_ = (opt_params && opt_params.extensionId) || ''; + + /** + * Extension name for extension managed printers. + * @private {string} + */ + this.extensionName_ = (opt_params && opt_params.extensionName) || ''; }; /** * Prefix of the location destination tag. - * @type {!Array.<string>} + * @type {!Array<string>} * @const */ Destination.LOCATION_TAG_PREFIXES = [ @@ -195,7 +209,8 @@ cr.define('print_preview', function() { COOKIES: 'cookies', PROFILE: 'profile', DEVICE: 'device', - PRIVET: 'privet' + PRIVET: 'privet', + EXTENSION: 'extension' }; /** @@ -280,6 +295,7 @@ cr.define('print_preview', function() { /** @return {boolean} Whether the destination is local or cloud-based. */ get isLocal() { return this.origin_ == Destination.Origin.LOCAL || + this.origin_ == Destination.Origin.EXTENSION || (this.origin_ == Destination.Origin.PRIVET && this.connectionStatus_ != Destination.ConnectionStatus.UNREGISTERED); @@ -291,6 +307,14 @@ cr.define('print_preview', function() { }, /** + * @return {boolean} Whether the destination is an extension managed + * printer. + */ + get isExtension() { + return this.origin_ == Destination.Origin.EXTENSION; + }, + + /** * @return {string} The location of the destination, or an empty string if * the location is unknown. */ @@ -326,10 +350,10 @@ cr.define('print_preview', function() { this.id_ == Destination.GooglePromotedId.FEDEX) { return this.account_; } - return this.location || this.description; + return this.location || this.extensionName || this.description; }, - /** @return {!Array.<string>} Tags associated with the destination. */ + /** @return {!Array<string>} Tags associated with the destination. */ get tags() { return this.tags_.slice(0); }, @@ -339,6 +363,22 @@ cr.define('print_preview', function() { return this.cloudID_; }, + /** + * @return {string} Extension ID associated with the destination. Non-empty + * only for extension managed printers. + */ + get extensionId() { + return this.extensionId_; + }, + + /** + * @return {string} Extension name associated with the destination. + * Non-empty only for extension managed printers. + */ + get extensionName() { + return this.extensionName_; + }, + /** @return {?print_preview.Cdd} Print capabilities of the destination. */ get capabilities() { return this.capabilities_; @@ -442,7 +482,7 @@ cr.define('print_preview', function() { }, /** - * @return {!Array.<string>} Properties (besides display name) to match + * @return {!Array<string>} Properties (besides display name) to match * search queries against. */ get extraPropertiesToMatch() { @@ -457,6 +497,7 @@ cr.define('print_preview', function() { */ matches: function(query) { return !!this.displayName_.match(query) || + !!this.extensionName_.match(query) || this.extraPropertiesToMatch.some(function(property) { return property.match(query); }); diff --git a/chromium/chrome/browser/resources/print_preview/data/destination_store.js b/chromium/chrome/browser/resources/print_preview/data/destination_store.js index 8eb788bdd75..b261ce27879 100644 --- a/chromium/chrome/browser/resources/print_preview/data/destination_store.js +++ b/chromium/chrome/browser/resources/print_preview/data/destination_store.js @@ -48,14 +48,14 @@ cr.define('print_preview', function() { /** * 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 destinations by origin and id. - * @type {Object.<string, !print_preview.Destination>} + * @type {Object<string, !print_preview.Destination>} * @private */ this.destinationMap_ = {}; @@ -100,7 +100,7 @@ cr.define('print_preview', function() { /** * Maps user account to the list of origins for which destinations are * already loaded. - * @type {!Object.<string, Array.<print_preview.Destination.Origin>>} + * @type {!Object<string, Array<print_preview.Destination.Origin>>} * @private */ this.loadedCloudOrigins_ = {}; @@ -154,6 +154,29 @@ cr.define('print_preview', function() { this.privetSearchTimeout_ = null; /** + * Whether a search for extension destinations is in progress. + * @type {boolean} + * @private + */ + this.isExtensionDestinationSearchInProgress_ = false; + + /** + * Whether the destination store has already loaded all extension + * destinations. + * @type {boolean} + * @private + */ + this.hasLoadedAllExtensionDestinations_ = false; + + /** + * ID of a timeout set at the start of an extension destination search. The + * timeout ends the search. + * @type {?number} + * @private + */ + this.extensionSearchTimeout_ = null; + + /** * MDNS service name of destination that we are waiting to register. * @type {?string} * @private @@ -198,7 +221,16 @@ cr.define('print_preview', function() { * @const * @private */ - DestinationStore.PRIVET_SEARCH_DURATION_ = 2000; + DestinationStore.PRIVET_SEARCH_DURATION_ = 5000; + + /** + * Maximum amount of time spent searching for extension destinations, in + * milliseconds. + * @type {number} + * @const + * @private + */ + DestinationStore.EXTENSION_SEARCH_DURATION_ = 5000; /** * Localizes printer capabilities. @@ -217,10 +249,13 @@ cr.define('print_preview', function() { 'NA_LEDGER': 'Tabloid' }; for (var i = 0, media; media = mediaSize.option[i]; i++) { - media.custom_display_name = - media.custom_display_name || - mediaDisplayNames[media.name] || - media.name; + // No need to patch capabilities with localized names provided. + if (!media.custom_display_name_localized) { + media.custom_display_name = + media.custom_display_name || + mediaDisplayNames[media.name] || + media.name; + } } } return capabilities; @@ -232,7 +267,7 @@ cr.define('print_preview', function() { /** * @param {string=} opt_account Account to filter destinations by. When * omitted, all destinations are returned. - * @return {!Array.<!print_preview.Destination>} List of destinations + * @return {!Array<!print_preview.Destination>} List of destinations * accessible by the {@code account}. */ destinations: function(opt_account) { @@ -264,7 +299,8 @@ cr.define('print_preview', function() { */ get isLocalDestinationSearchInProgress() { return this.isLocalDestinationSearchInProgress_ || - this.isPrivetDestinationSearchInProgress_; + this.isPrivetDestinationSearchInProgress_ || + this.isExtensionDestinationSearchInProgress_; }, /** @@ -291,11 +327,10 @@ cr.define('print_preview', function() { !this.appState_.selectedDestinationOrigin) { this.selectDefaultDestination_(); } else { - assert(typeof this.appState_.selectedDestinationAccount == 'string'); var key = this.getDestinationKey_( this.appState_.selectedDestinationOrigin, this.appState_.selectedDestinationId, - this.appState_.selectedDestinationAccount); + this.appState_.selectedDestinationAccount || ''); var candidate = this.destinationMap_[key]; if (candidate != null) { this.selectDestination(candidate); @@ -311,7 +346,7 @@ cr.define('print_preview', function() { this.cloudPrintInterface_.printer( this.appState_.selectedDestinationId, this.appState_.selectedDestinationOrigin, - this.appState_.selectedDestinationAccount); + this.appState_.selectedDestinationAccount || ''); } else if (this.appState_.selectedDestinationOrigin == print_preview.Destination.Origin.PRIVET) { // TODO(noamsml): Resolve a specific printer instead of listing all @@ -336,6 +371,29 @@ cr.define('print_preview', function() { cr.dispatchSimpleEvent( this, DestinationStore.EventType.CACHED_SELECTED_DESTINATION_INFO_READY); + } else if (this.appState_.selectedDestinationOrigin == + print_preview.Destination.Origin.EXTENSION) { + // TODO(tbarzic): Add support for requesting a single extension's + // printer list. + this.startLoadExtensionDestinations(); + + this.selectedDestination_ = + print_preview.ExtensionDestinationParser.parse({ + extensionId: this.appState_.selectedDestinationExtensionId, + extensionName: this.appState_.selectedDestinationExtensionName, + id: this.appState_.selectedDestinationId, + name: this.appState_.selectedDestinationName || '' + }); + + if (this.appState_.selectedDestinationCapabilities) { + this.selectedDestination_.capabilities = + this.appState_.selectedDestinationCapabilities; + + cr.dispatchSimpleEvent( + this, + DestinationStore.EventType + .CACHED_SELECTED_DESTINATION_INFO_READY); + } } else { this.selectDefaultDestination_(); } @@ -434,8 +492,10 @@ cr.define('print_preview', function() { if (destination.isPrivet) { this.nativeLayer_.startGetPrivetDestinationCapabilities( destination.id); - } - else if (destination.isLocal) { + } else if (destination.isExtension) { + this.nativeLayer_.startGetExtensionDestinationCapabilities( + destination.id); + } else if (destination.isLocal) { this.nativeLayer_.startGetLocalDestinationCapabilities( destination.id); } else { @@ -478,6 +538,8 @@ cr.define('print_preview', function() { /** Initiates loading of privet print destinations. */ startLoadPrivetDestinations: function() { if (!this.hasLoadedAllPrivetDestinations_) { + if (this.privetDestinationSearchInProgress_) + clearTimeout(this.privetSearchTimeout_); this.isPrivetDestinationSearchInProgress_ = true; this.nativeLayer_.startGetPrivetDestinations(); cr.dispatchSimpleEvent( @@ -488,6 +550,23 @@ cr.define('print_preview', function() { } }, + /** Initializes loading of extension managed print destinations. */ + startLoadExtensionDestinations: function() { + if (this.hasLoadedAllExtensionDestinations_) + return; + + if (this.isExtensionDestinationSearchInProgress_) + clearTimeout(this.extensionSearchTimeout_); + + this.isExtensionDestinationSearchInProgress_ = true; + this.nativeLayer_.startGetExtensionDestinations(); + cr.dispatchSimpleEvent( + this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED); + this.extensionSearchTimeout_ = setTimeout( + this.endExtensionPrinterSearch_.bind(this), + DestinationStore.EXTENSION_SEARCH_DURATION_); + }, + /** * Initiates loading of cloud destinations. * @param {print_preview.Destination.Origin=} opt_origin Search destinations @@ -523,6 +602,7 @@ cr.define('print_preview', function() { this.startLoadCloudDestinations(); this.startLoadLocalDestinations(); this.startLoadPrivetDestinations(); + this.startLoadExtensionDestinations(); }, /** @@ -549,7 +629,7 @@ cr.define('print_preview', function() { /** * Inserts multiple {@code destinations} to the data store and dispatches * single DESTINATIONS_INSERTED event. - * @param {!Array.<print_preview.Destination>} destinations Print + * @param {!Array<print_preview.Destination>} destinations Print * destinations to insert. * @private */ @@ -627,6 +707,21 @@ cr.define('print_preview', function() { }, /** + * Called when loading of extension managed printers is done. + * @private + */ + endExtensionPrinterSearch_: function() { + this.isExtensionDestinationSearchInProgress_ = false; + this.hasLoadedAllExtensionDestinations_ = true; + cr.dispatchSimpleEvent( + this, DestinationStore.EventType.DESTINATION_SEARCH_DONE); + // Clear initially selected (cached) extension destination if it hasn't + // been found among reported extension destinations. + if (this.isInAutoSelectMode_ && this.selectedDestination_.isExtension) + this.selectDefaultDestination_(); + }, + + /** * Inserts a destination into the store without dispatching any events. * @return {boolean} Whether the inserted destination was not already in the * store. @@ -679,6 +774,14 @@ cr.define('print_preview', function() { this.nativeLayer_, print_preview.NativeLayer.EventType.PRIVET_CAPABILITIES_SET, this.onPrivetCapabilitiesSet_.bind(this)); + this.tracker_.add( + this.nativeLayer_, + print_preview.NativeLayer.EventType.EXTENSION_PRINTERS_ADDED, + this.onExtensionPrintersAdded_.bind(this)); + this.tracker_.add( + this.nativeLayer_, + print_preview.NativeLayer.EventType.EXTENSION_CAPABILITIES_SET, + this.onExtensionCapabilitiesSet_.bind(this)); }, /** @@ -710,6 +813,8 @@ cr.define('print_preview', function() { this.selectDestination(null); this.loadedCloudOrigins_ = {}; this.hasLoadedAllLocalDestinations_ = false; + this.hasLoadedAllPrivetDestinations_ = false; + this.hasLoadedAllExtensionDestinations_ = false; clearTimeout(this.autoSelectTimeout_); this.autoSelectTimeout_ = setTimeout( @@ -885,7 +990,6 @@ cr.define('print_preview', function() { * @private */ onPrivetCapabilitiesSet_: function(event) { - var destinationId = event.printerId; var destinations = print_preview.PrivetDestinationParser.parse(event.printer); destinations.forEach(function(dest) { @@ -895,6 +999,43 @@ cr.define('print_preview', function() { }, /** + * Called when an extension responds to a getExtensionDestinations + * request. + * @param {Object} event Contains information about list of printers + * reported by the extension. + * {@code done} parameter is set iff this is the final list of printers + * returned as part of getExtensionDestinations request. + * @private + */ + onExtensionPrintersAdded_: function(event) { + this.insertDestinations_(event.printers.map(function(printer) { + return print_preview.ExtensionDestinationParser.parse(printer); + })); + + if (event.done && this.isExtensionDestinationSearchInProgress_) { + clearTimeout(this.extensionSearchTimeout_); + this.endExtensionPrinterSearch_(); + } + }, + + /** + * Called when capabilities for an extension managed printer are set. + * @param {Object} event Contains the printer's capabilities and ID. + * @private + */ + onExtensionCapabilitiesSet_: function(event) { + var destinationKey = this.getDestinationKey_( + print_preview.Destination.Origin.EXTENSION, + event.printerId, + '' /* account */); + var destination = this.destinationMap_[destinationKey]; + if (!destination) + return; + destination.capabilities = event.capabilities; + this.updateDestination_(destination); + }, + + /** * Called from native layer after the user was requested to sign in, and did * so successfully. * @private diff --git a/chromium/chrome/browser/resources/print_preview/data/invitation_store.js b/chromium/chrome/browser/resources/print_preview/data/invitation_store.js index 80720362764..86ba438ecf1 100644 --- a/chromium/chrome/browser/resources/print_preview/data/invitation_store.js +++ b/chromium/chrome/browser/resources/print_preview/data/invitation_store.js @@ -22,14 +22,14 @@ cr.define('print_preview', function() { /** * Maps user account to the list of invitations for this account. - * @private {!Object.<string, !Array.<!print_preview.Invitation>>} + * @private {!Object<string, !Array<!print_preview.Invitation>>} */ this.invitations_ = {}; /** * Maps user account to the flag whether the invitations for this account * were successfully loaded. - * @private {!Object.<string, print_preview.InvitationStore.LoadStatus_>} + * @private {!Object<string, print_preview.InvitationStore.LoadStatus_>} */ this.loadStatus_ = {}; @@ -87,7 +87,7 @@ cr.define('print_preview', function() { /** * @param {string} account Account to filter invitations by. - * @return {!Array.<!print_preview.Invitation>} List of invitations for the + * @return {!Array<!print_preview.Invitation>} List of invitations for the * {@code account}. */ invitations: function(account) { diff --git a/chromium/chrome/browser/resources/print_preview/data/local_parsers.js b/chromium/chrome/browser/resources/print_preview/data/local_parsers.js index c15fb593490..d367134e04e 100644 --- a/chromium/chrome/browser/resources/print_preview/data/local_parsers.js +++ b/chromium/chrome/browser/resources/print_preview/data/local_parsers.js @@ -37,7 +37,7 @@ cr.define('print_preview', function() { /** * Parses a privet destination as one or more local printers. * @param {!Object} destinationInfo Object that describes a privet printer. - * @return {!Array.<!print_preview.Destination>} Parsed destination info. + * @return {!Array<!print_preview.Destination>} Parsed destination info. */ PrivetDestinationParser.parse = function(destinationInfo) { var returnedPrinters = []; @@ -66,9 +66,31 @@ cr.define('print_preview', function() { return returnedPrinters; }; + function ExtensionDestinationParser() {} + + /** + * Parses an extension destination from an extension supplied printer + * description. + * @param {!Object} destinationInfo Object describing an extension printer. + * @return {!print_preview.Destination} Parsed destination. + */ + ExtensionDestinationParser.parse = function(destinationInfo) { + return new print_preview.Destination( + destinationInfo.id, + print_preview.Destination.Type.LOCAL, + print_preview.Destination.Origin.EXTENSION, + destinationInfo.name, + false /* isRecent */, + print_preview.Destination.ConnectionStatus.ONLINE, + {description: destinationInfo.description || '', + extensionId: destinationInfo.extensionId, + extensionName: destinationInfo.extensionName || ''}); + }; + // Export return { LocalDestinationParser: LocalDestinationParser, - PrivetDestinationParser: PrivetDestinationParser + PrivetDestinationParser: PrivetDestinationParser, + ExtensionDestinationParser: ExtensionDestinationParser }; }); diff --git a/chromium/chrome/browser/resources/print_preview/data/margins.js b/chromium/chrome/browser/resources/print_preview/data/margins.js index 2b5497151c8..c09c0d5197d 100644 --- a/chromium/chrome/browser/resources/print_preview/data/margins.js +++ b/chromium/chrome/browser/resources/print_preview/data/margins.js @@ -16,7 +16,7 @@ cr.define('print_preview', function() { function Margins(top, right, bottom, left) { /** * Backing store for the margin values in points. - * @type {!Object.< + * @type {!Object< * !print_preview.ticket_items.CustomMargins.Orientation, number>} * @private */ diff --git a/chromium/chrome/browser/resources/print_preview/data/measurement_system.js b/chromium/chrome/browser/resources/print_preview/data/measurement_system.js index ef28f86f4d1..6acab16743f 100644 --- a/chromium/chrome/browser/resources/print_preview/data/measurement_system.js +++ b/chromium/chrome/browser/resources/print_preview/data/measurement_system.js @@ -24,7 +24,7 @@ cr.define('print_preview', function() { * Parses |numberFormat| and extracts the symbols used for the thousands point * and decimal point. * @param {string} numberFormat The formatted version of the number 12345678. - * @return {!Array.<string>} The extracted symbols in the order + * @return {!Array<string>} The extracted symbols in the order * [thousandsSymbol, decimalSymbol]. For example, * parseNumberFormat("123,456.78") returns [",", "."]. */ @@ -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/chromium/chrome/browser/resources/print_preview/data/page_number_set.js b/chromium/chrome/browser/resources/print_preview/data/page_number_set.js index 3dd7827f7a9..2b081a64ec3 100644 --- a/chromium/chrome/browser/resources/print_preview/data/page_number_set.js +++ b/chromium/chrome/browser/resources/print_preview/data/page_number_set.js @@ -7,14 +7,14 @@ cr.define('print_preview', function() { /** * An immutable ordered set of page numbers. - * @param {!Array.<number>} pageNumberList A list of page numbers to include + * @param {!Array<number>} pageNumberList A list of page numbers to include * in the set. * @constructor */ function PageNumberSet(pageNumberList) { /** * Internal data store for the page number set. - * @type {!Array.<number>} + * @type {!Array<number>} * @private */ this.pageNumberSet_ = pageListToPageSet(pageNumberList); @@ -51,7 +51,7 @@ cr.define('print_preview', function() { return this.pageNumberSet_.indexOf(pageNumber); }, - /** @return {!Array.<number>} Array representation of the set. */ + /** @return {!Array<number>} Array representation of the set. */ asArray: function() { return this.pageNumberSet_.slice(0); }, diff --git a/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js b/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js index 0ca75a4ac5a..66414b45a8b 100644 --- a/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js +++ b/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js @@ -376,7 +376,7 @@ cr.define('print_preview', function() { if (this.appState_.hasField( print_preview.AppState.Field.VENDOR_OPTIONS)) { this.vendorItems_.updateValue( - /** @type {!Object.<string, string>} */(this.appState_.getField( + /** @type {!Object<string, string>} */(this.appState_.getField( print_preview.AppState.Field.VENDOR_OPTIONS))); } }, @@ -406,9 +406,10 @@ cr.define('print_preview', function() { * @return {!Object} Google Cloud Print print ticket. */ createPrintTicket: function(destination) { - assert(!destination.isLocal || destination.isPrivet, + assert(!destination.isLocal || + destination.isPrivet || destination.isExtension, 'Trying to create a Google Cloud Print print ticket for a local ' + - ' non-privet destination'); + ' non-privet and non-extension destination'); assert(destination.capabilities, 'Trying to create a Google Cloud Print print ticket for a ' + diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js index 11ddd7fc223..b1cbe3838fa 100644 --- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js +++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/color.js @@ -24,13 +24,13 @@ cr.define('print_preview.ticket_items', function() { }; /** - * @private {!Array.<string>} List of capability types considered color. + * @private {!Array<string>} List of capability types considered color. * @const */ Color.COLOR_TYPES_ = ['STANDARD_COLOR', 'CUSTOM_COLOR']; /** - * @private {!Array.<string>} List of capability types considered monochrome. + * @private {!Array<string>} List of capability types considered monochrome. * @const */ Color.MONOCHROME_TYPES_ = ['STANDARD_MONOCHROME', 'CUSTOM_MONOCHROME']; @@ -114,9 +114,9 @@ cr.define('print_preview.ticket_items', function() { }, /** - * @param {!Array.<!Object.<{type: (string|undefined), + * @param {!Array<!Object<{type: (string|undefined), * is_default: (boolean|undefined)}>>} options - * @return {Object.<{type: (string|undefined), + * @return {Object<{type: (string|undefined), * is_default: (boolean|undefined)}>} Default color * option of the given list. * @private diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js index 9e4fc4f38d5..38ffc00b5fe 100644 --- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js +++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/custom_margins.js @@ -37,7 +37,7 @@ cr.define('print_preview.ticket_items', function() { /** * Mapping of a margin orientation to its opposite. - * @type {!Object.<!print_preview.ticket_items.CustomMargins.Orientation, + * @type {!Object<!print_preview.ticket_items.CustomMargins.Orientation, * !print_preview.ticket_items.CustomMargins.Orientation>} * @private */ diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js index 013263bbdc5..bbb3f8229a2 100644 --- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js +++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/page_range.js @@ -65,7 +65,7 @@ cr.define('print_preview.ticket_items', function() { }, /** - * @return {!Array.<Object.<{from: number, to: number}>>} A list of page + * @return {!Array<Object<{from: number, to: number}>>} A list of page * ranges. */ getPageRanges: function() { @@ -73,7 +73,7 @@ cr.define('print_preview.ticket_items', function() { }, /** - * @return {!Array.<object.<{from: number, to: number}>>} A list of page + * @return {!Array<object<{from: number, to: number}>>} A list of page * ranges suitable for use in the native layer. * TODO(vitalybuka): this should be removed when native layer switched to * page ranges. diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js index b347ff8a2b3..e3cf19f8ace 100644 --- a/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js +++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/vendor_items.js @@ -37,7 +37,7 @@ cr.define('print_preview.ticket_items', function() { /** * Vendor ticket items store, maps item id to the item value. - * @private {!Object.<string, string>} + * @private {!Object<string, string>} */ this.items_ = {}; }; @@ -78,14 +78,14 @@ cr.define('print_preview.ticket_items', function() { /** * Vendor ticket items store, maps item id to the item value. - * @return {!Object.<string, string>} + * @return {!Object<string, string>} */ get ticketItems() { return this.items_; }, /** - * @param {!Object.<string, string>} values Values to set as the values of + * @param {!Object<string, string>} values Values to set as the values of * vendor ticket items. Maps vendor item id to the value. */ updateValue: function(values) { diff --git a/chromium/chrome/browser/resources/print_preview/data/user_info.js b/chromium/chrome/browser/resources/print_preview/data/user_info.js index 88967cefded..0d7ade2238d 100644 --- a/chromium/chrome/browser/resources/print_preview/data/user_info.js +++ b/chromium/chrome/browser/resources/print_preview/data/user_info.js @@ -24,7 +24,7 @@ cr.define('print_preview', function() { /** * Email addresses of the logged in users or empty array if no user is * logged in. {@code null} if not known yet. - * @private {?Array.<string>} + * @private {?Array<string>} */ this.users_ = null; }; @@ -68,7 +68,7 @@ cr.define('print_preview', function() { }, /** - * @return {?Array.<string>} Email addresses of the logged in users or + * @return {?Array<string>} Email addresses of the logged in users or * empty array if no user is logged in. {@code null} if not known yet. */ get users() { @@ -78,7 +78,7 @@ cr.define('print_preview', function() { /** * Sets logged in user accounts info. * @param {string} activeUser Active user account (email). - * @param {!Array.<string>} users List of currently logged in accounts. + * @param {!Array<string>} users List of currently logged in accounts. */ setUsers: function(activeUser, users) { this.activeUser_ = activeUser; diff --git a/chromium/chrome/browser/resources/print_preview/native_layer.js b/chromium/chrome/browser/resources/print_preview/native_layer.js index ca7ff32c84f..8c72a538284 100644 --- a/chromium/chrome/browser/resources/print_preview/native_layer.js +++ b/chromium/chrome/browser/resources/print_preview/native_layer.js @@ -36,6 +36,8 @@ cr.define('print_preview', function() { this.onFailedToGetPrinterCapabilities_.bind(this); global.failedToGetPrivetPrinterCapabilities = this.onFailedToGetPrivetPrinterCapabilities_.bind(this); + global.failedToGetExtensionPrinterCapabilities = + this.onFailedToGetExtensionPrinterCapabilities_.bind(this); global.reloadPrintersList = this.onReloadPrintersList_.bind(this); global.printToCloud = this.onPrintToCloud_.bind(this); global.fileSelectionCancelled = @@ -51,16 +53,20 @@ cr.define('print_preview', function() { this.onDidGetPreviewPageCount_.bind(this); global.onDidPreviewPage = this.onDidPreviewPage_.bind(this); global.updatePrintPreview = this.onUpdatePrintPreview_.bind(this); - global.printScalingDisabledForSourcePDF = - this.onPrintScalingDisabledForSourcePDF_.bind(this); global.onDidGetAccessToken = this.onDidGetAccessToken_.bind(this); global.autoCancelForTesting = this.autoCancelForTesting_.bind(this); global.onPrivetPrinterChanged = this.onPrivetPrinterChanged_.bind(this); global.onPrivetCapabilitiesSet = this.onPrivetCapabilitiesSet_.bind(this); global.onPrivetPrintFailed = this.onPrivetPrintFailed_.bind(this); + global.onExtensionPrintersAdded = + this.onExtensionPrintersAdded_.bind(this); + global.onExtensionCapabilitiesSet = + this.onExtensionCapabilitiesSet_.bind(this); global.onEnableManipulateSettingsForTest = this.onEnableManipulateSettingsForTest_.bind(this); + global.printPresetOptionsFromDocument = + this.onPrintPresetOptionsFromDocument_.bind(this); }; /** @@ -95,6 +101,11 @@ cr.define('print_preview', function() { PRIVET_CAPABILITIES_SET: 'print_preview.NativeLayer.PRIVET_CAPABILITIES_SET', PRIVET_PRINT_FAILED: 'print_preview.NativeLayer.PRIVET_PRINT_FAILED', + EXTENSION_PRINTERS_ADDED: + 'print_preview.NativeLayer.EXTENSION_PRINTERS_ADDED', + EXTENSION_CAPABILITIES_SET: + 'print_preview.NativeLayer.EXTENSION_CAPABILITIES_SET', + PRINT_PRESET_OPTIONS: 'print_preview.NativeLayer.PRINT_PRESET_OPTIONS', }; /** @@ -176,6 +187,24 @@ cr.define('print_preview', function() { }, /** + * Requests that extension system dispatches an event requesting the list of + * extension managed printers. + */ + startGetExtensionDestinations: function() { + chrome.send('getExtensionPrinters'); + }, + + /** + * Requests an extension destination's printing capabilities. A + * EXTENSION_CAPABILITIES_SET event will be dispatched in response. + * @param {string} destinationId The ID of the destination whose + * capabilities are requested. + */ + startGetExtensionDestinationCapabilities: function(destinationId) { + chrome.send('getExtensionPrinterCapabilities', [destinationId]); + }, + + /** * Requests the destination's printing capabilities. A CAPABILITIES_SET * event will be dispatched in response. * @param {string} destinationId ID of the destination. @@ -236,6 +265,7 @@ cr.define('print_preview', function() { print_preview.Destination.GooglePromotedId.SAVE_AS_PDF, 'printWithCloudPrint': destination != null && !destination.isLocal, 'printWithPrivet': destination != null && destination.isPrivet, + 'printWithExtension': destination != null && destination.isExtension, 'deviceName': destination == null ? 'foo' : destination.id, 'generateDraftData': documentInfo.isModifiable, 'fitToPageEnabled': printTicketStore.fitToPage.getValue(), @@ -318,6 +348,7 @@ cr.define('print_preview', function() { print_preview.Destination.GooglePromotedId.SAVE_AS_PDF, 'printWithCloudPrint': !destination.isLocal, 'printWithPrivet': destination.isPrivet, + 'printWithExtension': destination.isExtension, 'deviceName': destination.id, 'isFirstRequest': false, 'requestID': -1, @@ -348,7 +379,7 @@ cr.define('print_preview', function() { }; } - if (destination.isPrivet) { + if (destination.isPrivet || destination.isExtension) { ticket['ticket'] = printTicketStore.createPrintTicket(destination); ticket['capabilities'] = JSON.stringify(destination.capabilities); } @@ -397,9 +428,14 @@ cr.define('print_preview', function() { chrome.send('manageLocalPrinters'); }, - /** Navigates the user to the Google Cloud Print management page. */ - startManageCloudDestinations: function() { - chrome.send('manageCloudPrinters'); + /** + * Navigates the user to the Google Cloud Print management page. + * @param {?string} user Email address of the user to open the management + * page for (user must be currently logged in, indeed) or {@code null} + * to open this page for the primary user. + */ + startManageCloudDestinations: function(user) { + chrome.send('manageCloudPrinters', [user || '']); }, /** Forces browser to open a new tab with the given URL address. */ @@ -508,6 +544,21 @@ cr.define('print_preview', function() { this.dispatchEvent(getCapsFailEvent); }, + /** + * Called when native layer fails to get settings information for a + * requested extension destination. + * @param {string} destinationId Printer affected by error. + * @private + */ + onFailedToGetExtensionPrinterCapabilities_: function(destinationId) { + var getCapsFailEvent = new Event( + NativeLayer.EventType.GET_CAPABILITIES_FAIL); + getCapsFailEvent.destinationId = destinationId; + getCapsFailEvent.destinationOrigin = + print_preview.Destination.Origin.EXTENSION; + this.dispatchEvent(getCapsFailEvent); + }, + /** Reloads the printer list. */ onReloadPrintersList_: function() { cr.dispatchSimpleEvent(this, NativeLayer.EventType.DESTINATIONS_RELOAD); @@ -652,15 +703,18 @@ cr.define('print_preview', function() { }, /** - * Updates the fit to page option state based on the print scaling option of - * source pdf. PDF's have an option to enable/disable print scaling. When we - * find out that the print scaling option is disabled for the source pdf, we - * uncheck the fitToPage_ to page checkbox. This function is called from C++ - * code. + * Updates print preset options from source PDF document. + * Called from PrintPreviewUI::OnSetOptionsFromDocument(). + * @param {{disableScaling: boolean, copies: number, + * duplex: number}} options Specifies + * printing options according to source document presets. * @private */ - onPrintScalingDisabledForSourcePDF_: function() { - cr.dispatchSimpleEvent(this, NativeLayer.EventType.DISABLE_SCALING); + onPrintPresetOptionsFromDocument_: function(options) { + var printPresetOptionsEvent = new Event( + NativeLayer.EventType.PRINT_PRESET_OPTIONS); + printPresetOptionsEvent.optionsFromDocument = options; + this.dispatchEvent(printPresetOptionsEvent); }, /** @@ -712,6 +766,37 @@ cr.define('print_preview', function() { }, /** + * @param {Array<!{extensionId: string, + * extensionName: string, + * id: string, + * name: string, + * description: (string|undefined)}>} printers The list + * containing information about printers added by an extension. + * @param {boolean} done Whether this is the final list of extension + * managed printers. + */ + onExtensionPrintersAdded_: function(printers, done) { + var event = new Event(NativeLayer.EventType.EXTENSION_PRINTERS_ADDED); + event.printers = printers; + event.done = done; + this.dispatchEvent(event); + }, + + /** + * Called when an extension responds to a request for an extension printer + * capabilities. + * @param {string} printerId The printer's ID. + * @param {!Object} capabilities The reported printer capabilities. + */ + onExtensionCapabilitiesSet_: function(printerId, + capabilities) { + var event = new Event(NativeLayer.EventType.EXTENSION_CAPABILITIES_SET); + event.printerId = printerId; + event.capabilities = capabilities; + this.dispatchEvent(event); + }, + + /** * Allows for onManipulateSettings to be called * from the native layer. * @private diff --git a/chromium/chrome/browser/resources/print_preview/preview_generator.js b/chromium/chrome/browser/resources/print_preview/preview_generator.js index bcbe95fe64a..597300f9fe3 100644 --- a/chromium/chrome/browser/resources/print_preview/preview_generator.js +++ b/chromium/chrome/browser/resources/print_preview/preview_generator.js @@ -94,7 +94,7 @@ cr.define('print_preview', function() { /** * Page ranges setting used used to generate the last preview. - * @type {!Array.<object.<{from: number, to: number}>>} + * @type {!Array<object<{from: number, to: number}>>} * @private */ this.pageRanges_ = null; diff --git a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.css b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.css index 7eb6a1ff019..747be8993ae 100644 --- a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.css +++ b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control.css @@ -56,7 +56,6 @@ box-sizing: border-box; color: white; cursor: auto; - font-family: arial; font-size: 0.8em; height: 25px; padding: 5px 0; diff --git a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js index ceab20b7c7f..5615cddb93c 100644 --- a/chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js +++ b/chromium/chrome/browser/resources/print_preview/previewarea/margin_control_container.js @@ -14,11 +14,15 @@ cr.define('print_preview', function() { * Used to read and write custom margin values. * @param {!print_preview.MeasurementSystem} measurementSystem Used to convert * between the system's local units and points. + * @param {function(boolean)} dragChangedCallback A function which is called + * when dragging margins starts or stops. True is passed to the function + * if the margin is currently being dragged and false otherwise. * @constructor * @extends {print_preview.Component} */ function MarginControlContainer(documentInfo, marginsTypeTicketItem, - customMarginsTicketItem, measurementSystem) { + customMarginsTicketItem, measurementSystem, + dragChangedCallback) { print_preview.Component.call(this); /** @@ -48,8 +52,17 @@ cr.define('print_preview', function() { this.measurementSystem_ = measurementSystem; /** + * Called in response to dragging the margins starting or stopping. True is + * passed to the function if the margin is currently being dragged and false + * otherwise. + * @type {function(boolean)} + * @private + */ + this.dragChangedCallback_ = dragChangedCallback; + + /** * Convenience array that contains all of the margin controls. - * @type {!Object.< + * @type {!Object< * !print_preview.ticket_items.CustomMargins.Orientation, * !print_preview.MarginControl>} * @private @@ -307,6 +320,7 @@ cr.define('print_preview', function() { MarginControlContainer.isTopOrBottom_(control.getOrientation()) ? MarginControlContainer.Classes_.DRAGGING_VERTICAL : MarginControlContainer.Classes_.DRAGGING_HORIZONTAL); + this.dragChangedCallback_(true); }, /** @@ -348,6 +362,7 @@ cr.define('print_preview', function() { this.draggedControl_.getOrientation(), this.draggedControl_.getPositionInPts()); this.draggedControl_ = null; + this.dragChangedCallback_(false); } }, diff --git a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.css b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.css index 78725eefdd5..ef12a1c2f9e 100644 --- a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.css +++ b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.css @@ -78,14 +78,3 @@ #preview-area .preview-area-open-system-dialog-button-throbber { vertical-align: middle; } - -.preview-area-overlayed { - /** - * The 100 ms delay here is intended to match that of - * #preview-area .preview-area-overlay-layer.invisible - * This is important because without this delay there will be a noticeable - * flicker whenever the overlay is displayed for a short period of time. - */ - transition: visibility 100ms linear 100ms; - visibility: hidden; -} diff --git a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js index 8a33f4ec1d2..9b5aa86ec78 100644 --- a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js +++ b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js @@ -108,7 +108,8 @@ cr.define('print_preview', function() { this.documentInfo_, this.printTicketStore_.marginsType, this.printTicketStore_.customMargins, - this.printTicketStore_.measurementSystem); + this.printTicketStore_.measurementSystem, + this.onMarginDragChanged_.bind(this)); this.addChild(this.marginControlContainer_); /** @@ -200,7 +201,6 @@ cr.define('print_preview', function() { OPEN_SYSTEM_DIALOG_BUTTON_THROBBER: 'preview-area-open-system-dialog-button-throbber', OVERLAY: 'preview-area-overlay-layer', - OVERLAYED: 'preview-area-overlayed', MARGIN_CONTROL: 'margin-control', PREVIEW_AREA: 'preview-area-plugin-wrapper' }; @@ -231,7 +231,7 @@ cr.define('print_preview', function() { /** * Maps message IDs to the CSS class that contains them. - * @type {Object.<print_preview.PreviewArea.MessageId_, string>} + * @type {Object<print_preview.PreviewArea.MessageId_, string>} * @private */ PreviewArea.MessageIdClassMap_ = {}; @@ -300,11 +300,21 @@ cr.define('print_preview', function() { // No scroll bar anywhere, or the active element is something else, like a // button. Note: buttons have a bigger scrollHeight than clientHeight. - this.plugin_.sendKeyEvent(e.keyCode); + this.plugin_.sendKeyEvent(e); e.preventDefault(); }, /** + * Set a callback that gets called when a key event is received that + * originates in the plugin. + * @param {function(Event)} callback The callback to be called with a key + * event. + */ + setPluginKeyEventCallback: function(callback) { + this.keyEventCallback_ = callback; + }, + + /** * Shows a custom message on the preview area's overlay. * @param {string} message Custom message to show. */ @@ -525,14 +535,12 @@ cr.define('print_preview', function() { var marginControls = this.getElement().getElementsByClassName( PreviewArea.Classes_.MARGIN_CONTROL); for (var i = 0; i < marginControls.length; ++i) { - marginControls[i].classList.toggle(PreviewArea.Classes_.OVERLAYED, - visible); + marginControls[i].setAttribute('aria-hidden', visible); } var previewAreaControls = this.getElement().getElementsByClassName( PreviewArea.Classes_.PREVIEW_AREA); for (var i = 0; i < previewAreaControls.length; ++i) { - previewAreaControls[i].classList.toggle(PreviewArea.Classes_.OVERLAYED, - visible); + previewAreaControls[i].setAttribute('aria-hidden', visible); } if (!visible) { @@ -563,6 +571,7 @@ cr.define('print_preview', function() { } else { this.plugin_ = /** @type {print_preview.PDFPlugin} */( PDFCreateOutOfProcessPlugin(srcUrl)); + this.plugin_.setKeyEventCallback(this.keyEventCallback_); } this.plugin_.setAttribute('class', 'preview-area-plugin'); @@ -793,6 +802,22 @@ cr.define('print_preview', function() { this.marginControlContainer_.updateClippingMask( new print_preview.Size(viewportWidth, viewportHeight)); } + }, + + /** + * Called when dragging margins starts or stops. + * @param {boolean} isDragging True if the margin is currently being dragged + * and false otherwise. + */ + onMarginDragChanged_: function(isDragging) { + if (!this.plugin_) + return; + + // When hovering over the plugin (which may be in a separate iframe) + // pointer events will be sent to the frame. When dragging the margins, + // we don't want this to happen as it can cause the margin to stop + // being draggable. + this.plugin_.style.pointerEvents = isDragging ? 'none' : 'auto'; } }; diff --git a/chromium/chrome/browser/resources/print_preview/print_header.js b/chromium/chrome/browser/resources/print_preview/print_header.js index cc0895643fa..33dcdb8bbbb 100644 --- a/chromium/chrome/browser/resources/print_preview/print_header.js +++ b/chromium/chrome/browser/resources/print_preview/print_header.js @@ -83,6 +83,8 @@ cr.define('print_preview', function() { var summaryEl = this.getChildElement('.summary'); summaryEl.innerHTML = ''; summaryEl.textContent = message; + this.getChildElement('button.print').classList.toggle('loading', false); + this.getChildElement('button.cancel').classList.toggle('loading', false); }, /** @override */ diff --git a/chromium/chrome/browser/resources/print_preview/print_preview.html b/chromium/chrome/browser/resources/print_preview/print_preview.html index b697e2e4cb2..2c8e44eb417 100644 --- a/chromium/chrome/browser/resources/print_preview/print_preview.html +++ b/chromium/chrome/browser/resources/print_preview/print_preview.html @@ -1,5 +1,6 @@ -<!DOCTYPE html> -<html i18n-values="dir:textdirection;" id="print-preview" class="focus-outline-visible"> +<!doctype html> +<html id="print-preview" class="focus-outline-visible" + i18n-values="dir:textdirection;lang:language"> <head> <meta charset="utf-8"> @@ -50,7 +51,7 @@ <script src="chrome://print/strings.js"></script> </head> -<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize"> +<body> <div id="navbar-container"> <header> <h1 id="navbar-content-title" i18n-content="title"></h1> @@ -103,7 +104,7 @@ <include src="search/destination_list_item.html"> <include src="search/fedex_tos.html"> - <script src="chrome://resources/js/i18n_template2.js"></script> + <script src="chrome://resources/js/i18n_template.js"></script> </body> </html> diff --git a/chromium/chrome/browser/resources/print_preview/print_preview.js b/chromium/chrome/browser/resources/print_preview/print_preview.js index 673b8d89ef1..cb2434132c1 100644 --- a/chromium/chrome/browser/resources/print_preview/print_preview.js +++ b/chromium/chrome/browser/resources/print_preview/print_preview.js @@ -347,8 +347,8 @@ cr.define('print_preview', function() { this.onSettingsInvalid_.bind(this)); this.tracker.add( this.nativeLayer_, - print_preview.NativeLayer.EventType.DISABLE_SCALING, - this.onDisableScaling_.bind(this)); + print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS, + this.onPrintPresetOptionsFromDocument_.bind(this)); this.tracker.add( this.nativeLayer_, print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED, @@ -412,6 +412,7 @@ cr.define('print_preview', function() { this.onCancelButtonClick_.bind(this)); this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this)); + this.previewArea_.setPluginKeyEventCallback(this.onKeyDown_.bind(this)); this.tracker.add( this.destinationSettings_, @@ -528,6 +529,7 @@ cr.define('print_preview', function() { PrintPreview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW) { if ((this.destinationStore_.selectedDestination.isLocal && !this.destinationStore_.selectedDestination.isPrivet && + !this.destinationStore_.selectedDestination.isExtension && this.destinationStore_.selectedDestination.id != print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) || this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW) { @@ -870,15 +872,12 @@ cr.define('print_preview', function() { // Escape key closes the dialog. if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) { -<if expr="toolkit_views"> - // On the toolkit_views environment, ESC key is handled by C++-side - // instead of JS-side. - return; -</if> -<if expr="not toolkit_views"> - this.close_(); -</if> - e.preventDefault(); + // On non-mac with toolkit-views, ESC key is handled by C++-side instead + // of JS-side. + if (cr.isMac) { + this.close_(); + e.preventDefault(); + } return; } @@ -955,7 +954,7 @@ cr.define('print_preview', function() { * @private */ onManageCloudDestinationsActivated_: function() { - this.nativeLayer_.startManageCloudDestinations(); + this.nativeLayer_.startManageCloudDestinations(this.userInfo_.activeUser); }, /** @@ -979,13 +978,27 @@ cr.define('print_preview', function() { }, /** - * Called when the native layer dispatches a DISABLE_SCALING event. Resets - * fit-to-page selection and updates document info. + * Updates printing options according to source document presets. + * @param {Event} event Contains options from source document. * @private */ - onDisableScaling_: function() { - this.printTicketStore_.fitToPage.updateValue(null); - this.documentInfo_.updateIsScalingDisabled(true); + onPrintPresetOptionsFromDocument_: function(event) { + if (event.optionsFromDocument.disableScaling) { + this.printTicketStore_.fitToPage.updateValue(null); + this.documentInfo_.updateIsScalingDisabled(true); + } + + if (event.optionsFromDocument.copies > 0 && + this.printTicketStore_.copies.isCapabilityAvailable()) { + this.printTicketStore_.copies.updateValue( + event.optionsFromDocument.copies); + } + + if (event.optionsFromDocument.duplex >= 0 && + this.printTicketStore_.duplex.isCapabilityAvailable()) { + this.printTicketStore_.duplex.updateValue( + event.optionsFromDocument.duplex); + } }, /** diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_page.html b/chromium/chrome/browser/resources/print_preview/print_preview_page.html deleted file mode 100644 index d7a9de8e723..00000000000 --- a/chromium/chrome/browser/resources/print_preview/print_preview_page.html +++ /dev/null @@ -1,117 +0,0 @@ -<!DOCTYPE html> -<head> -<style> - body { - margin: 0px; - width: 0px; - } - .row { - display: table-row; - vertical-align: inherit; - } - #header, #footer { - display: table; - table-layout:fixed; - width: inherit; - } - #header { - vertical-align: top; - } - #footer { - vertical-align: bottom; - } - .text { - display: table-cell; - font-family: sans-serif; - font-size: 8px; - vertical-align: inherit; - white-space: nowrap; - } - #page_number { - text-align: right; - } - #title { - text-align: center; - } - #date, #url { - padding-left: 0.7cm; - padding-right: 0.1cm; - } - #title, #page_number { - padding-left: 0.1cm; - padding-right: 0.7cm; - } - #title, #url { - overflow: hidden; - text-overflow: ellipsis; - } - #title, #date { - padding-bottom: 0cm; - padding-top: 0.4cm; - } - #page_number, #url { - padding-bottom: 0.4cm; - padding-top: 0cm; - } -</style> -<script> - -function pixels(value) { - return value + 'px'; -} - -function setup(options) { - var body = document.querySelector('body'); - var header = document.querySelector('#header'); - var content = document.querySelector('#content'); - var footer = document.querySelector('#footer'); - - body.style.width = pixels(options['width']); - body.style.height = pixels(options['height']); - header.style.height = pixels(options['topMargin']); - content.style.height = pixels(options['height'] - options['topMargin'] - - options['bottomMargin']); - footer.style.height = pixels(options['bottomMargin']); - - document.querySelector('#date span').innerText = - new Date(options['date']).toLocaleDateString(); - document.querySelector('#title span').innerText = options['title']; - - document.querySelector('#url span').innerText = options['url']; - document.querySelector('#page_number span').innerText = options['pageNumber']; - - // Reduce date and page number space to give more space to title and url. - document.querySelector('#date').style.width = - pixels(document.querySelector('#date span').offsetWidth); - document.querySelector('#page_number').style.width = - pixels(document.querySelector('#page_number span').offsetWidth); - - // Hide text if it doesn't fit into expected margins. - if (header.offsetHeight > options['topMargin'] + 1) { - header.style.display = 'none'; - content.style.height = pixels(options['height'] - options['bottomMargin']); - } - if (footer.offsetHeight > options['bottomMargin'] + 1) { - footer.style.display = 'none'; - } -} - -</script> -</head> -<body> - <div id="header"> - <div class="row"> - <div id="date" class="text"><span/></div> - <div id="title" class="text"><span/></div> - </div> - </div> - <div id="content"> - </div> - <div id="footer"> - <div class="row"> - <div id="url" class="text"><span/></div> - <div id="page_number" class="text"><span/></div> - </div> - </div> -</body> -</html> diff --git a/chromium/chrome/browser/resources/print_preview/print_preview_utils.js b/chromium/chrome/browser/resources/print_preview/print_preview_utils.js index 18740b9dd5e..49a367b51b5 100644 --- a/chromium/chrome/browser/resources/print_preview/print_preview_utils.js +++ b/chromium/chrome/browser/resources/print_preview/print_preview_utils.js @@ -23,8 +23,8 @@ function isPositiveInteger(value) { /** * Returns true if the contents of the two arrays are equal. - * @param {Array.<{from: number, to: number}>} array1 The first array. - * @param {Array.<{from: number, to: number}>} array2 The second array. + * @param {Array<{from: number, to: number}>} array1 The first array. + * @param {Array<{from: number, to: number}>} array2 The second array. * @return {boolean} true if the arrays are equal. */ function areArraysEqual(array1, array2) { @@ -56,8 +56,8 @@ function areRangesEqual(array1, array2) { /** * Removes duplicate elements from |inArray| and returns a new array. * |inArray| is not affected. It assumes that |inArray| is already sorted. - * @param {!Array.<number>} inArray The array to be processed. - * @return {!Array.<number>} The array after processing. + * @param {!Array<number>} inArray The array to be processed. + * @return {!Array<number>} The array after processing. */ function removeDuplicates(inArray) { var out = []; @@ -94,7 +94,7 @@ function removeDuplicates(inArray) { * Example: "1-4dsf, 11" is invalid regardless of |totalPageCount|. * @param {string} pageRangeText The text to be checked. * @param {number=} opt_totalPageCount The total number of pages. - * @return {Array.<{from: number, to: number}>} An array of page range objects. + * @return {Array<{from: number, to: number}>} An array of page range objects. */ function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) { if (pageRangeText == '') { @@ -141,7 +141,7 @@ function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) { * See pageRangeTextToPageRanges for details. * @param {string} pageRangeText The text to be checked. * @param {number} totalPageCount The total number of pages. - * @return {Array.<number>} A list of all pages. + * @return {Array<number>} A list of all pages. */ function pageRangeTextToPageList(pageRangeText, totalPageCount) { var pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount); @@ -162,8 +162,8 @@ function pageRangeTextToPageList(pageRangeText, totalPageCount) { } /** - * @param {!Array.<number>} pageList The list to be processed. - * @return {!Array.<number>} The contents of |pageList| in ascending order and + * @param {!Array<number>} pageList The list to be processed. + * @return {!Array<number>} The contents of |pageList| in ascending order and * without any duplicates. |pageList| is not affected. */ function pageListToPageSet(pageList) { @@ -203,3 +203,32 @@ function setIsVisible(element, isVisible) { function arrayContains(array, item) { return array.indexOf(item) != -1; } + +/** + * @param {!goog.array.ArrayLike<!{locale: string, value: string}>} + * localizedStrings An array of strings with corresponding locales. + * @param {string} locale Locale to look the string up for. + * @return {string} A string for the requested {@code locale}. An empty string + * if there's no string for the specified locale found. + */ +function getStringForLocale(localizedStrings, locale) { + locale = locale.toLowerCase(); + for (var i = 0; i < localizedStrings.length; i++) { + if (localizedStrings[i].locale.toLowerCase() == locale) + return localizedStrings[i].value; + } + return ''; +} + +/** + * @param {!goog.array.ArrayLike<!{locale: string, value: string}>} + * localizedStrings An array of strings with corresponding locales. + * @return {string} A string for the current locale. An empty string if there's + * no string for the current locale found. + */ +function getStringForCurrentLocale(localizedStrings) { + // First try to find an exact match and then look for the language only. + return getStringForLocale(localizedStrings, navigator.language) || + getStringForLocale(localizedStrings, + navigator.language.split('-')[0]); +} diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_list.js b/chromium/chrome/browser/resources/print_preview/search/destination_list.js index 4bb18d0ea00..861125801ef 100644 --- a/chromium/chrome/browser/resources/print_preview/search/destination_list.js +++ b/chromium/chrome/browser/resources/print_preview/search/destination_list.js @@ -45,14 +45,14 @@ cr.define('print_preview', function() { /** * Backing store for the destination list. - * @type {!Array.<print_preview.Destination>} + * @type {!Array<print_preview.Destination>} * @private */ this.destinations_ = []; /** * Set of destination ids. - * @type {!Object.<string, boolean>} + * @type {!Object<string, boolean>} * @private */ this.destinationIds_ = {}; @@ -80,7 +80,7 @@ cr.define('print_preview', function() { /** * List items representing destinations. - * @type {!Array.<!print_preview.DestinationListItem>} + * @type {!Array<!print_preview.DestinationListItem>} * @private */ this.listItems_ = []; @@ -151,6 +151,14 @@ cr.define('print_preview', function() { DestinationList.HEIGHT_OF_ITEM_); }, + /** + * @return {Element} The element that contains this one. Used for height + * calculations. + */ + getContainerElement: function() { + return this.getElement().parentNode; + }, + /** @param {boolean} isVisible Whether the throbber is visible. */ setIsThrobberVisible: function(isVisible) { setIsVisible(this.getChildElement('.throbber-container'), isVisible); @@ -198,7 +206,7 @@ cr.define('print_preview', function() { /** * Updates the destinations to render in the destination list. - * @param {!Array.<print_preview.Destination>} destinations Destinations to + * @param {!Array<print_preview.Destination>} destinations Destinations to * render. */ updateDestinations: function(destinations) { @@ -251,7 +259,7 @@ cr.define('print_preview', function() { /** * Renders all destinations in the given list. - * @param {!Array.<print_preview.Destination>} destinations List of + * @param {!Array<print_preview.Destination>} destinations List of * destinations to render. * @private */ @@ -290,10 +298,13 @@ cr.define('print_preview', function() { var focusedEl = listEl.querySelector(':focus'); for (var i = 0; i < numItems; i++) { var listItem = visibleListItems[destinations[i].id]; - if (listItem) - this.updateListItem_(listEl, listItem, focusedEl); - else + if (listItem) { + // Destination ID is the same, but it can be registered to a different + // user account, hence passing it to the item update. + this.updateListItem_(listEl, listItem, focusedEl, destinations[i]); + } else { this.renderListItem_(listEl, destinations[i]); + } } }, @@ -301,10 +312,11 @@ cr.define('print_preview', function() { * @param {Element} listEl List element. * @param {!print_preview.DestinationListItem} listItem List item to update. * @param {Element} focusedEl Currently focused element within the listEl. + * @param {!print_preview.Destination} destination Destination to render. * @private */ - updateListItem_: function(listEl, listItem, focusedEl) { - listItem.update(this.query_); + updateListItem_: function(listEl, listItem, focusedEl, destination) { + listItem.update(destination, this.query_); var itemEl = listItem.getElement(); // Preserve focused inner element, if there's one. diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.css b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.css index 22663fd0b99..3501f28cf02 100644 --- a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.css +++ b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.css @@ -72,3 +72,29 @@ .destination-list-item-query-highlight { background-color: rgba(255, 240, 120, 0.9); } + +.extension-controlled-indicator { + display: flex; + flex: 1; + justify-content: flex-end; + min-width: 150px; +} + +.extension-name { + -webkit-margin-start: 1em; + color: #999; + line-height: 24px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.extension-icon { + background-position: center; + background-repeat: no-repeat; + cursor: pointer; + flex: 0 0 auto; + height: 24px; + margin: 0 3px; + width: 24px; +} diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.html b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.html index 1168e82b328..2348e0e6455 100644 --- a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.html +++ b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.html @@ -9,5 +9,9 @@ class="register-promo-button"> </button> </span> + <span class="extension-controlled-indicator" hidden> + <span class="extension-name"></span> + <span class="extension-icon" role="button" tabindex="0"></span> + </span> </span> </li> diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js index cf5358281ab..48b5b8174f7 100644 --- a/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js +++ b/chromium/chrome/browser/resources/print_preview/search/destination_list_item.js @@ -88,9 +88,12 @@ cr.define('print_preview', function() { /** * Updates the list item UI state. + * @param {!print_preview.Destination} destination Destination data object + * to render. * @param {RegExp} query Active filter query. */ - update: function(query) { + update: function(destination, query) { + this.destination_ = destination; this.query_ = query; this.updateUi_(); }, @@ -129,6 +132,34 @@ cr.define('print_preview', function() { } nameEl.title = textContent; + if (this.destination_.isExtension) { + var extensionNameEl = this.getChildElement('.extension-name'); + var extensionName = this.destination_.extensionName; + extensionNameEl.title = this.destination_.extensionName; + if (this.query_) { + extensionNameEl.textContent = ''; + this.addTextWithHighlight_(extensionNameEl, extensionName); + } else { + extensionNameEl.textContent = this.destination_.extensionName; + } + + var extensionIconEl = this.getChildElement('.extension-icon'); + extensionIconEl.style.backgroundImage = '-webkit-image-set(' + + 'url(chrome://extension-icon/' + + this.destination_.extensionId + '/24/1) 1x,' + + 'url(chrome://extension-icon/' + + this.destination_.extensionId + '/48/1) 2x)'; + extensionIconEl.title = loadTimeData.getStringF( + 'extensionDestinationIconTooltip', + this.destination_.extensionName); + extensionIconEl.onclick = this.onExtensionIconClicked_.bind(this); + extensionIconEl.onkeydown = this.onExtensionIconKeyDown_.bind(this); + } + + var extensionIndicatorEl = + this.getChildElement('.extension-controlled-indicator'); + setIsVisible(extensionIndicatorEl, this.destination_.isExtension); + // Initialize the element which renders the destination's offline status. this.getElement().classList.toggle('stale', this.destination_.isOffline); var offlineStatusEl = this.getChildElement('.offline-status'); @@ -229,6 +260,32 @@ cr.define('print_preview', function() { DestinationListItem.EventType.REGISTER_PROMO_CLICKED); promoClickedEvent.destination = this.destination_; this.eventTarget_.dispatchEvent(promoClickedEvent); + }, + + /** + * Handles click and 'Enter' key down events for the extension icon element. + * It opens extensions page with the extension associated with the + * destination highlighted. + * @param {MouseEvent|KeyboardEvent} e The event to handle. + * @private + */ + onExtensionIconClicked_: function(e) { + e.stopPropagation(); + window.open('chrome://extensions?id=' + this.destination_.extensionId); + }, + + /** + * Handles key down event for the extensin icon element. Keys different than + * 'Enter' are ignored. + * @param {KeyboardEvent} e The event to handle. + * @private + */ + onExtensionIconKeyDown_: function(e) { + if (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey) + return; + if (e.keyCode != 13 /* Enter */) + return; + this.onExtensionIconClicked_(event); } }; diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_search.css b/chromium/chrome/browser/resources/print_preview/search/destination_search.css index 5d014d2cdfd..ea76b84d8da 100644 --- a/chromium/chrome/browser/resources/print_preview/search/destination_search.css +++ b/chromium/chrome/browser/resources/print_preview/search/destination_search.css @@ -64,11 +64,14 @@ padding: 0 14px 18px; } +#destination-search .lists > :last-child { + padding-bottom: 0; +} + #destination-search .invitation-container { -webkit-animation: invitation-fadein 500ms; - background-color: rgb(249, 237, 190); - border-top: solid 1px rgb(245, 233, 183); - padding: 12px; + -webkit-box-align: center; + -webkit-box-orient: vertical; } @-webkit-keyframes invitation-fadein { @@ -82,7 +85,6 @@ #destination-search .invitation-text { padding-bottom: 12px; - text-align: center; } #destination-search .invitation-buttons { @@ -102,9 +104,6 @@ #destination-search .cloudprint-promo { -webkit-box-align: center; -webkit-user-select: none; - background-color: rgb(249, 237, 190); - display: -webkit-box; - padding: 12px; } #destination-search .cloudprint-promo .sign-in[is='action-link'] { @@ -125,8 +124,8 @@ #destination-search .cloudprint-promo .close-button { -webkit-margin-start: 12px; background-image: -webkit-image-set( - url('chrome://theme/IDR_CLOSE_DIALOG') 1x, - url('chrome://theme/IDR_CLOSE_DIALOG@2x') 2x); + url(chrome://theme/IDR_CLOSE_DIALOG) 1x, + url(chrome://theme/IDR_CLOSE_DIALOG@2x) 2x); background-repeat: no-repeat; background-size: 14px; height: 14px; @@ -135,12 +134,12 @@ #destination-search .cloudprint-promo .close-button:hover { background-image: -webkit-image-set( - url('chrome://theme/IDR_CLOSE_DIALOG_H') 1x, - url('chrome://theme/IDR_CLOSE_DIALOG_H@2x') 2x); + url(chrome://theme/IDR_CLOSE_DIALOG_H) 1x, + url(chrome://theme/IDR_CLOSE_DIALOG_H@2x) 2x); } #destination-search .cloudprint-promo .close-button:active { background-image: -webkit-image-set( - url('chrome://theme/IDR_CLOSE_DIALOG_P') 1x, - url('chrome://theme/IDR_CLOSE_DIALOG_P@2x') 2x); + url(chrome://theme/IDR_CLOSE_DIALOG_P) 1x, + url(chrome://theme/IDR_CLOSE_DIALOG_P@2x) 2x); } diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_search.html b/chromium/chrome/browser/resources/print_preview/search/destination_search.html index 8cbc6f80841..556c61190df 100644 --- a/chromium/chrome/browser/resources/print_preview/search/destination_search.html +++ b/chromium/chrome/browser/resources/print_preview/search/destination_search.html @@ -12,7 +12,12 @@ <div class="local-list"></div> <div class="cloud-list" hidden></div> </div> - <div class="invitation-container" hidden> + <div class="action-area"> + <div class="button-strip"> + <button class="cancel-button" i18n-content="cancel"></button> + </div> + </div> + <div class="invitation-container gray-bottom-bar" hidden> <div class="invitation-text"></div> <div class="invitation-buttons"> <button class="invitation-accept-button"></button> @@ -21,8 +26,8 @@ <div id="invitation-process-throbber" class="throbber" hidden></div> </div> </div> - <div class="cloudprint-promo" hidden> - <img src="../images/cloud.png" class="icon"> + <div class="cloudprint-promo gray-bottom-bar" hidden> + <img src="../images/cloud.png" class="icon" alt=""> <div class="promo-text"></div> <div class="close-button"></div> </div> diff --git a/chromium/chrome/browser/resources/print_preview/search/destination_search.js b/chromium/chrome/browser/resources/print_preview/search/destination_search.js index 9ebd9d49890..601022408df 100644 --- a/chromium/chrome/browser/resources/print_preview/search/destination_search.js +++ b/chromium/chrome/browser/resources/print_preview/search/destination_search.js @@ -123,14 +123,6 @@ cr.define('print_preview', function() { }; /** - * Padding at the bottom of a destination list in pixels. - * @type {number} - * @const - * @private - */ - DestinationSearch.LIST_BOTTOM_PADDING_ = 18; - - /** * Number of unregistered destinations that may be promoted to the top. * @type {number} * @const @@ -264,6 +256,11 @@ cr.define('print_preview', function() { print_preview.UserInfo.EventType.USERS_CHANGED, this.onUsersChanged_.bind(this)); + this.tracker.add( + this.getChildElement('.button-strip .cancel-button'), + 'click', + this.cancel.bind(this)); + this.tracker.add(window, 'resize', this.onWindowResize_.bind(this)); this.updateThrobbers_(); @@ -297,7 +294,8 @@ cr.define('print_preview', function() { parseInt(elStyle.getPropertyValue('padding-bottom'), 10) - this.getChildElement('.lists').offsetTop - this.getChildElement('.invitation-container').offsetHeight - - this.getChildElement('.cloudprint-promo').offsetHeight; + this.getChildElement('.cloudprint-promo').offsetHeight - + this.getChildElement('.action-area').offsetHeight; }, /** @@ -384,8 +382,9 @@ cr.define('print_preview', function() { var getListsTotalHeight = function(lists, counts) { return lists.reduce(function(sum, list, index) { + var container = list.getContainerElement(); return sum + list.getEstimatedHeightInPixels(counts[index]) + - DestinationSearch.LIST_BOTTOM_PADDING_; + parseInt(window.getComputedStyle(container).paddingBottom, 10); }, 0); }; var getCounts = function(lists, count) { @@ -482,14 +481,14 @@ cr.define('print_preview', function() { if (invitation.asGroupManager) { invitationText = loadTimeData.getStringF( 'groupPrinterSharingInviteText', - invitation.sender, - invitation.destination.displayName, - invitation.receiver); + HTMLEscape(invitation.sender), + HTMLEscape(invitation.destination.displayName), + HTMLEscape(invitation.receiver)); } else { invitationText = loadTimeData.getStringF( 'printerSharingInviteText', - invitation.sender, - invitation.destination.displayName); + HTMLEscape(invitation.sender), + HTMLEscape(invitation.destination.displayName)); } this.getChildElement('.invitation-text').innerHTML = invitationText; @@ -679,6 +678,7 @@ cr.define('print_preview', function() { */ onCloudprintPromoCloseButtonClick_: function() { setIsVisible(this.getChildElement('.cloudprint-promo'), false); + this.reflowLists_(); }, /** diff --git a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.html b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.html index a947d0766fb..d3a72a8afb5 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.html +++ b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.html @@ -11,9 +11,9 @@ </div> <div class="action-area"> <div class="button-strip"> - <button id="cancel-button" i18n-content="cancel"></button> - <button id="done-button" i18n-content="advancedSettingsDialogConfirm" - class="default-button"></button> + <button class="cancel-button" i18n-content="cancel"></button> + <button class="done-button default-button" + i18n-content="advancedSettingsDialogConfirm"></button> </div> </div> </div> diff --git a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js index 969b19dc52f..892dbc82e46 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js +++ b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings.js @@ -35,7 +35,7 @@ cr.define('print_preview', function() { /** @private {print_preview.Destination} */ this.destination_ = null; - /** @private {!Array.<!print_preview.AdvancedSettingsItem>} */ + /** @private {!Array<!print_preview.AdvancedSettingsItem>} */ this.items_ = []; }; @@ -70,12 +70,12 @@ cr.define('print_preview', function() { print_preview.Overlay.prototype.enterDocument.call(this); this.tracker.add( - this.getChildElement('#cancel-button'), + this.getChildElement('.button-strip .cancel-button'), 'click', this.cancel.bind(this)); this.tracker.add( - this.getChildElement('#done-button'), + this.getChildElement('.button-strip .done-button'), 'click', this.onApplySettings_.bind(this)); @@ -110,7 +110,7 @@ cr.define('print_preview', function() { /** @override */ onEnterPressedInternal: function() { - var doneButton = this.getChildElement('#done-button'); + var doneButton = this.getChildElement('.button-strip .done-button'); if (!doneButton.disabled) doneButton.click(); return !doneButton.disabled; diff --git a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js index 71cff811f59..b8ae300e5e6 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js +++ b/chromium/chrome/browser/resources/print_preview/settings/advanced_settings/advanced_settings_item.js @@ -151,35 +151,50 @@ cr.define('print_preview', function() { if (this.query_) { var optionMatches = (this.selectedValue_ || '').match(this.query_); // Even if there's no match anymore, keep the item visible to do not - // surprise user. - if (optionMatches) - this.showSearchBubble_(optionMatches[0]); - else + // surprise user. Even if there's a match, do not show the bubble, user + // is already aware that this option is visible and matches the search. + // Showing the bubble will only create a distraction by moving UI + // elements around. + if (!optionMatches) this.hideSearchBubble_(); } }, /** + * @param {!Object} entity Entity to get the display name for. Entity in + * is either a vendor capability or vendor capability option. + * @return {string} The entity display name. + * @private + */ + getEntityDisplayName_: function(entity) { + var displayName = entity.display_name; + if (!displayName && entity.display_name_localized) + displayName = getStringForCurrentLocale(entity.display_name_localized); + return displayName || ''; + }, + + /** * Renders capability properties according to the current state. * @private */ renderCapability_: function() { - var textContent = this.capability_.display_name; + var textContent = this.getEntityDisplayName_(this.capability_); + // Whether capability name matches the query. var nameMatches = this.query_ ? !!textContent.match(this.query_) : true; + // An array of text segments of the capability value matching the query. var optionMatches = null; if (this.query_) { if (this.capability_.type == 'SELECT') { - this.capability_.select_cap.option.some(function(option) { - optionMatches = (option.display_name || '').match(this.query_); - return !!optionMatches; - }.bind(this)); + // Look for the first option that matches the query. + for (var i = 0; i < this.select_.length && !optionMatches; i++) + optionMatches = this.select_.options[i].text.match(this.query_); } else { optionMatches = (this.text_.value || '').match(this.query_); } } - var matches = nameMatches || optionMatches; + var matches = nameMatches || !!optionMatches; - if (!matches || !optionMatches) + if (!optionMatches) this.hideSearchBubble_(); setIsVisible(this.getElement(), matches); @@ -246,17 +261,17 @@ cr.define('print_preview', function() { */ initializeSelectValue_: function() { setIsVisible( - this.getChildElement('.advanced-settings-item-value-select'), true); + this.getChildElement('.advanced-settings-item-value-select'), true); var selectEl = this.select_; var indexToSelect = 0; this.capability_.select_cap.option.forEach(function(option, index) { var item = document.createElement('option'); - item.text = option.display_name; + item.text = this.getEntityDisplayName_(option); item.value = option.value; if (option.is_default) indexToSelect = index; selectEl.appendChild(item); - }); + }, this); for (var i = 0, option; option = selectEl.options[i]; i++) { if (option.value == this.selectedValue_) { indexToSelect = i; diff --git a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html index 29036e018f5..42c7bff00c1 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html +++ b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html @@ -5,9 +5,13 @@ <div class="right-column"> <div id="copies-settings-box"> <input class="copies" type="text" value="1" maxlength="3" - aria-labelledby="copies-label"> - <button class="increment" i18n-values="title:incrementTitle;">+</button> - <button class="decrement" i18n-values="title:decrementTitle;">–</button> + aria-labelledby="copies-label" aria-live="polite" id="copies"> + <button class="increment" + i18n-values="title:incrementTitle;aria-label:incrementTitle" + aria-controls="copies">+</button> + <button class="decrement" + i18n-values="title:decrementTitle;aria-label:decrementTitle" + aria-controls="copies">–</button> <div class="collate-container checkbox" aria-live="polite" hidden><label> <input class="collate" type="checkbox" checked aria-labelledby="copies-collate-label"> diff --git a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js index 10814f9b811..ce5d5ef92e1 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js +++ b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js @@ -216,7 +216,11 @@ cr.define('print_preview', function() { */ onTextfieldBlur_: function() { if (this.getChildElement('input.copies').value == '') { - this.copiesTicketItem_.updateValue('1'); + // Do it asynchronously to avoid moving focus to Print button in + // PrintHeader.onTicketChange_. + setTimeout((function() { + this.copiesTicketItem_.updateValue('1'); + }).bind(this), 0); } }, diff --git a/chromium/chrome/browser/resources/print_preview/settings/destination_settings.css b/chromium/chrome/browser/resources/print_preview/settings/destination_settings.css index 31fe304dbb6..1962f1d7b79 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/destination_settings.css +++ b/chromium/chrome/browser/resources/print_preview/settings/destination_settings.css @@ -8,9 +8,7 @@ } #destination-settings .throbber { - display: block; - margin-bottom: 4px; - margin-top: 8px; + margin-top: 6px; } #destination-settings .destination-settings-box { diff --git a/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.css b/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.css index e436d225cd7..e029a64e906 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.css +++ b/chromium/chrome/browser/resources/print_preview/settings/dpi_settings.css @@ -2,7 +2,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#dpi-settings .dpi-settings-select { +#dpi-settings .settings-select { height: 28px; margin: 10px 0; } diff --git a/chromium/chrome/browser/resources/print_preview/settings/media_size_settings.css b/chromium/chrome/browser/resources/print_preview/settings/media_size_settings.css index b95dc49184f..bc69a775db4 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/media_size_settings.css +++ b/chromium/chrome/browser/resources/print_preview/settings/media_size_settings.css @@ -2,7 +2,7 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#media-size-settings .media-size-settings-select { +#media-size-settings .settings-select { height: 28px; margin: 10px 0; } diff --git a/chromium/chrome/browser/resources/print_preview/settings/more_settings.css b/chromium/chrome/browser/resources/print_preview/settings/more_settings.css index c35ec1000d9..0358173d521 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/more_settings.css +++ b/chromium/chrome/browser/resources/print_preview/settings/more_settings.css @@ -27,12 +27,12 @@ #more-settings .more-settings-icon-minus { background-image: -webkit-image-set( - url('../images/1x/minus.png') 1x, - url('../images/2x/minus.png') 2x); + url(../images/1x/minus.png) 1x, + url(../images/2x/minus.png) 2x); } #more-settings .more-settings-icon-plus { background-image: -webkit-image-set( - url('../images/1x/plus.png') 1x, - url('../images/2x/plus.png') 2x); + url(../images/1x/plus.png) 1x, + url(../images/2x/plus.png) 2x); } diff --git a/chromium/chrome/browser/resources/print_preview/settings/more_settings.js b/chromium/chrome/browser/resources/print_preview/settings/more_settings.js index 580b56ae5ab..c8e366286cd 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/more_settings.js +++ b/chromium/chrome/browser/resources/print_preview/settings/more_settings.js @@ -9,7 +9,7 @@ cr.define('print_preview', function() { * Toggles visibility of the specified printing options sections. * @param {!print_preview.DestinationStore} destinationStore To listen for * destination changes. - * @param {!Array.<print_preview.SettingsSection>} settingsSections Sections + * @param {!Array<print_preview.SettingsSection>} settingsSections Sections * to toggle by this component. * @constructor * @extends {print_preview.Component} @@ -20,7 +20,7 @@ cr.define('print_preview', function() { /** @private {!print_preview.DestinationStore} */ this.destinationStore_ = destinationStore; - /** @private {!Array.<print_preview.SettingsSection>} */ + /** @private {!Array<print_preview.SettingsSection>} */ this.settingsSections_ = settingsSections; /** @private {MoreSettings.SettingsToShow} */ diff --git a/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js b/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js index b32ce4d1535..0799c94e1c0 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js +++ b/chromium/chrome/browser/resources/print_preview/settings/settings_section_select.js @@ -79,28 +79,7 @@ cr.define('print_preview', function() { select.innerHTML = ''; this.ticketItem_.capability.option.forEach(function(option, index) { var selectOption = document.createElement('option'); - var displayName = option.custom_display_name; - if (!displayName && option.custom_display_name_localized) { - var getLocaleToCompare = - /** @type {function(string, boolean=): string} */ - (function(locale, opt_languageOnly) { - var code = opt_languageOnly ? locale.split('-')[0] : locale; - return code.toLowerCase(); - }); - var getItemForLocale = function(items, locale, languageOnly) { - locale = getLocaleToCompare(locale, languageOnly); - for (var i = 0; i < items.length; i++) { - if (getLocaleToCompare(items[i].locale) == locale) - return items[i].value; - } - return ''; - }; - var items = option.custom_display_name_localized; - displayName = - getItemForLocale(items, navigator.language, false) || - getItemForLocale(items, navigator.language, true); - } - selectOption.text = displayName || + selectOption.text = this.getCustomDisplayName_(option) || this.getDefaultDisplayName_(option); selectOption.value = JSON.stringify(option); select.appendChild(selectOption); @@ -121,6 +100,20 @@ cr.define('print_preview', function() { }, /** + * @param {!Object} option Option to get the custom display name for. + * @return {string} Custom display name for the option. + * @private + */ + getCustomDisplayName_: function(option) { + var displayName = option.custom_display_name; + if (!displayName && option.custom_display_name_localized) { + displayName = + getStringForCurrentLocale(option.custom_display_name_localized); + } + return displayName; + }, + + /** * @param {!Object} option Option to get the default display name for. * @return {string} Default option display name. * @private |