Chromium Code Reviews| Index: chrome/browser/resources/print_preview/data/destination_store.js | 
| diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js | 
| index b3739d70d05a7561182a37bbcc760a4b9b5aeac6..80aa095d16b7bdfe07393a48c5b90c94abb30956 100644 | 
| --- a/chrome/browser/resources/print_preview/data/destination_store.js | 
| +++ b/chrome/browser/resources/print_preview/data/destination_store.js | 
| @@ -69,24 +69,8 @@ cr.define('print_preview', function() { | 
| this.selectedDestination_ = null; | 
| /** | 
| - * Initial destination ID used to auto-select the first inserted destination | 
| - * that matches. If {@code null}, the first destination inserted into the | 
| - * store will be selected. | 
| - * @type {?string} | 
| - * @private | 
| - */ | 
| - this.initialDestinationId_ = null; | 
| - | 
| - /** | 
| - * Initial origin used to auto-select destination. | 
| - * @type {print_preview.Destination.Origin} | 
| - * @private | 
| - */ | 
| - this.initialDestinationOrigin_ = print_preview.Destination.Origin.LOCAL; | 
| - | 
| - /** | 
| * Whether the destination store will auto select the destination that | 
| - * matches the initial destination. | 
| + * matches the last used destination stored in appState_. | 
| * @type {boolean} | 
| * @private | 
| */ | 
| @@ -107,12 +91,12 @@ cr.define('print_preview', function() { | 
| this.cloudPrintInterface_ = null; | 
| /** | 
| - * Whether the destination store has already loaded or is loading all cloud | 
| - * destinations. | 
| - * @type {boolean} | 
| + * Maps user account to the list of origins for which destinations are | 
| + * already loaded. | 
| + * @type {!Object.<string, Array.<print_preview.Destination.Origin>>} | 
| * @private | 
| */ | 
| - this.hasLoadedAllCloudDestinations_ = false; | 
| + this.loadedCloudOrigins_ = {}; | 
| /** | 
| * ID of a timeout after the initial destination ID is set. If no inserted | 
| @@ -242,11 +226,19 @@ cr.define('print_preview', function() { | 
| __proto__: cr.EventTarget.prototype, | 
| /** | 
| - * @return {!Array.<!print_preview.Destination>} List of destinations in | 
| - * the store. | 
| + * @param {string=} opt_account Account to filter destinations by. When | 
| + * omitted, all destinations are returned. | 
| + * @return {!Array.<!print_preview.Destination>} List of destinations | 
| + * accessible by the {@code account}. | 
| */ | 
| - get destinations() { | 
| - return this.destinations_.slice(0); | 
| + destinations: function(opt_account) { | 
| + if (opt_account) { | 
| + return this.destinations_.filter(function(destination) { | 
| + return !destination.account || destination.account == opt_account; | 
| + }); | 
| + } else { | 
| + return this.destinations_.slice(0); | 
| + } | 
| }, | 
| /** | 
| @@ -278,41 +270,35 @@ cr.define('print_preview', function() { | 
| * destination. If any inserted destinations match this ID, that destination | 
| * will be automatically selected. This method must be called after the | 
| * print_preview.AppState has been initialized. | 
| - * @param {?string} systemDefaultDestinationId ID of the system default | 
| - * destination. | 
| * @private | 
| */ | 
| - init: function(systemDefaultDestinationId) { | 
| - if (this.appState_.selectedDestinationId && | 
| - this.appState_.selectedDestinationOrigin) { | 
| - this.initialDestinationId_ = this.appState_.selectedDestinationId; | 
| - this.initialDestinationOrigin_ = | 
| - this.appState_.selectedDestinationOrigin; | 
| - } else if (systemDefaultDestinationId) { | 
| 
 
Vitaly Buka (NO REVIEWS)
2014/04/11 02:32:57
separate change?
 
Aleksey Shlyapnikov
2014/04/11 19:09:29
Done.
 
 | 
| - this.initialDestinationId_ = systemDefaultDestinationId; | 
| - this.initialDestinationOrigin_ = print_preview.Destination.Origin.LOCAL; | 
| - } | 
| + init: function() { | 
| this.isInAutoSelectMode_ = true; | 
| - if (!this.initialDestinationId_ || !this.initialDestinationOrigin_) { | 
| + if (!this.appState_.selectedDestinationId || | 
| + !this.appState_.selectedDestinationOrigin) { | 
| this.onAutoSelectFailed_(); | 
| } else { | 
| - var key = this.getDestinationKey_(this.initialDestinationOrigin_, | 
| - this.initialDestinationId_); | 
| + var key = this.getDestinationKey_( | 
| + this.appState_.selectedDestinationOrigin, | 
| + this.appState_.selectedDestinationId, | 
| + this.appState_.selectedDestinationAccount); | 
| var candidate = this.destinationMap_[key]; | 
| if (candidate != null) { | 
| this.selectDestination(candidate); | 
| - } else if (this.initialDestinationOrigin_ == | 
| + } else if (this.appState_.selectedDestinationOrigin == | 
| print_preview.Destination.Origin.LOCAL) { | 
| this.nativeLayer_.startGetLocalDestinationCapabilities( | 
| - this.initialDestinationId_); | 
| + this.appState_.selectedDestinationId); | 
| } else if (this.cloudPrintInterface_ && | 
| - (this.initialDestinationOrigin_ == | 
| - print_preview.Destination.Origin.COOKIES || | 
| - this.initialDestinationOrigin_ == | 
| - print_preview.Destination.Origin.DEVICE)) { | 
| - this.cloudPrintInterface_.printer(this.initialDestinationId_, | 
| - this.initialDestinationOrigin_); | 
| - } else if (this.initialDestinationOrigin_ == | 
| + (this.appState_.selectedDestinationOrigin == | 
| + print_preview.Destination.Origin.COOKIES || | 
| + this.appState_.selectedDestinationOrigin == | 
| + print_preview.Destination.Origin.DEVICE)) { | 
| + this.cloudPrintInterface_.printer( | 
| + this.appState_.selectedDestinationId, | 
| + this.appState_.selectedDestinationOrigin, | 
| + this.appState_.selectedDestinationAccount); | 
| + } else if (this.appState_.selectedDestinationOrigin == | 
| print_preview.Destination.Origin.PRIVET) { | 
| // TODO(noamsml): Resolve a specific printer instead of listing all | 
| // privet printers in this case. | 
| @@ -324,7 +310,7 @@ cr.define('print_preview', function() { | 
| // destination store. When the real destination is created, this | 
| // destination will be overwritten. | 
| this.selectedDestination_ = new print_preview.Destination( | 
| - this.initialDestinationId_, | 
| + this.appState_.selectedDestinationId, | 
| print_preview.Destination.Type.LOCAL, | 
| print_preview.Destination.Origin.PRIVET, | 
| destinationName, | 
| @@ -357,7 +343,7 @@ cr.define('print_preview', function() { | 
| this.tracker_.add( | 
| this.cloudPrintInterface_, | 
| cloudprint.CloudPrintInterface.EventType.SEARCH_FAILED, | 
| - this.onCloudPrintSearchFailed_.bind(this)); | 
| + this.onCloudPrintSearchDone_.bind(this)); | 
| this.tracker_.add( | 
| this.cloudPrintInterface_, | 
| cloudprint.CloudPrintInterface.EventType.PRINTER_DONE, | 
| @@ -373,6 +359,7 @@ cr.define('print_preview', function() { | 
| * loaded. | 
| */ | 
| hasOnlyDefaultCloudDestinations: function() { | 
| + // TODO: Move the logic to print_preview. | 
| return this.destinations_.every(function(dest) { | 
| return dest.isLocal || | 
| dest.id == print_preview.Destination.GooglePromotedId.DOCS || | 
| @@ -382,30 +369,34 @@ cr.define('print_preview', function() { | 
| /** @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; | 
| + this.cancelAutoSelectTimeout_(); | 
| + if (destination == this.selectedDestination_) { | 
| + return; | 
| } | 
| + if (destination == null) { | 
| + this.selectedDestination_ = null; | 
| + cr.dispatchSimpleEvent( | 
| + this, DestinationStore.EventType.DESTINATION_SELECT); | 
| + return; | 
| + } | 
| + // Update and persist selected destination. | 
| + this.selectedDestination_ = destination; | 
| + this.selectedDestination_.isRecent = true; | 
| if (destination.id == print_preview.Destination.GooglePromotedId.FEDEX && | 
| !destination.isTosAccepted) { | 
| assert(this.cloudPrintInterface_ != null, | 
| - 'Selected FedEx Office destination, but Google Cloud Print is ' + | 
| - 'not enabled'); | 
| + 'Selected FedEx destination, but GCP API is not available'); | 
| destination.isTosAccepted = true; | 
| - this.cloudPrintInterface_.updatePrinterTosAcceptance(destination.id, | 
| - destination.origin, | 
| - true); | 
| + this.cloudPrintInterface_.updatePrinterTosAcceptance(destination, true); | 
| } | 
| this.appState_.persistSelectedDestination(this.selectedDestination_); | 
| - | 
| + // Adjust metrics. | 
| if (destination.cloudID && | 
| - this.destinations.some(function(otherDestination) { | 
| + this.destinations_.some(function(otherDestination) { | 
| return otherDestination.cloudID == destination.cloudID && | 
| otherDestination != destination; | 
| - })) { | 
| + })) { | 
| if (destination.isPrivet) { | 
| this.metrics_.incrementDestinationSearchBucket( | 
| print_preview.Metrics.DestinationSearchBucket. | 
| @@ -416,9 +407,10 @@ cr.define('print_preview', function() { | 
| CLOUD_DUPLICATE_SELECTED); | 
| } | 
| } | 
| - | 
| + // Notify about selected destination change. | 
| cr.dispatchSimpleEvent( | 
| this, DestinationStore.EventType.DESTINATION_SELECT); | 
| + // Request destination capabilities, of not known yet. | 
| if (destination.capabilities == null) { | 
| if (destination.isPrivet) { | 
| this.nativeLayer_.startGetPrivetDestinationCapabilities( | 
| @@ -429,10 +421,9 @@ cr.define('print_preview', function() { | 
| 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, | 
| - destination.origin); | 
| + 'Cloud destination selected, but GCP is not enabled'); | 
| + this.cloudPrintInterface_.printer( | 
| + destination.id, destination.origin, destination.account); | 
| } | 
| } else { | 
| cr.dispatchSimpleEvent( | 
| @@ -442,78 +433,16 @@ cr.define('print_preview', function() { | 
| }, | 
| /** | 
| - * Inserts a print destination to the data store and dispatches a | 
| - * DESTINATIONS_INSERTED event. If the destination matches the initial | 
| - * destination ID, then the destination will be automatically selected. | 
| - * @param {!print_preview.Destination} destination Print destination to | 
| - * insert. | 
| - */ | 
| - insertDestination: function(destination) { | 
| - if (this.insertDestination_(destination)) { | 
| - cr.dispatchSimpleEvent( | 
| - this, DestinationStore.EventType.DESTINATIONS_INSERTED); | 
| - if (this.isInAutoSelectMode_ && | 
| - this.matchInitialDestination_(destination.id, destination.origin)) { | 
| - this.selectDestination(destination); | 
| - } | 
| - } | 
| - }, | 
| - | 
| - /** | 
| - * Inserts multiple print destinations to the data store and dispatches one | 
| - * DESTINATIONS_INSERTED event. If any of the destinations match the initial | 
| - * destination ID, then that destination will be automatically selected. | 
| - * @param {!Array.<print_preview.Destination>} destinations Print | 
| - * destinations to insert. | 
| - */ | 
| - insertDestinations: function(destinations) { | 
| - var insertedDestination = false; | 
| - var destinationToAutoSelect = null; | 
| - destinations.forEach(function(dest) { | 
| - if (this.insertDestination_(dest)) { | 
| - insertedDestination = true; | 
| - if (this.isInAutoSelectMode_ && | 
| - destinationToAutoSelect == null && | 
| - this.matchInitialDestination_(dest.id, dest.origin)) { | 
| - destinationToAutoSelect = dest; | 
| - } | 
| - } | 
| - }, this); | 
| - if (insertedDestination) { | 
| - cr.dispatchSimpleEvent( | 
| - this, DestinationStore.EventType.DESTINATIONS_INSERTED); | 
| - } | 
| - if (destinationToAutoSelect != null) { | 
| - this.selectDestination(destinationToAutoSelect); | 
| - } | 
| - }, | 
| - | 
| - /** | 
| - * Updates an existing print destination with capabilities and display name | 
| - * information. If the destination doesn't already exist, it will be added. | 
| - * @param {!print_preview.Destination} destination Destination to update. | 
| - * @return {!print_preview.Destination} The existing destination that was | 
| - * updated or {@code null} if it was the new destination. | 
| + * Selects 'Save to PDF' destination (since it always exists). | 
| + * @private | 
| */ | 
| - updateDestination: function(destination) { | 
| - assert(destination.constructor !== Array, 'Single printer expected'); | 
| - var key = this.getDestinationKey_(destination.origin, destination.id); | 
| - var existingDestination = this.destinationMap_[key]; | 
| - if (existingDestination != null) { | 
| - existingDestination.capabilities = destination.capabilities; | 
| - } else { | 
| - this.insertDestination(destination); | 
| - } | 
| - | 
| - if (existingDestination == this.selectedDestination_ || | 
| - destination == this.selectedDestination_) { | 
| - this.appState_.persistSelectedDestination(this.selectedDestination_); | 
| - cr.dispatchSimpleEvent( | 
| - this, | 
| - DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); | 
| - } | 
| - | 
| - return existingDestination; | 
| + selectDefaultDestination_: function() { | 
| + var destination = this.destinationMap_[this.getDestinationKey_( | 
| + print_preview.Destination.Origin.LOCAL, | 
| + print_preview.Destination.GooglePromotedId.SAVE_AS_PDF, | 
| + '')] || null; | 
| + assert(destination != null, 'Save to PDF printer not found'); | 
| + this.selectDestination(destination); | 
| }, | 
| /** Initiates loading of local print destinations. */ | 
| @@ -546,12 +475,26 @@ cr.define('print_preview', function() { | 
| * for the specified origin only. | 
| */ | 
| startLoadCloudDestinations: function(opt_origin) { | 
| - if (this.cloudPrintInterface_ != null && | 
| - !this.hasLoadedAllCloudDestinations_) { | 
| - this.hasLoadedAllCloudDestinations_ = true; | 
| - this.cloudPrintInterface_.search(opt_origin); | 
| + if (this.cloudPrintInterface_ != null) { | 
| + var origins = this.loadedCloudOrigins_[this.userInfo_.activeUser] || []; | 
| + if (origins.length == 0 || | 
| + (opt_origin && origins.indexOf(opt_origin) < 0)) { | 
| + this.cloudPrintInterface_.search(opt_origin); | 
| + cr.dispatchSimpleEvent( | 
| + this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED); | 
| + } | 
| + } | 
| + }, | 
| + | 
| + /** Requests load of COOKIE based cloud destinations. */ | 
| + reloadUserCookieBasedDestinations: function() { | 
| + var origins = this.loadedCloudOrigins_[this.userInfo_.activeUser] || []; | 
| + if (origins.indexOf(print_preview.Destination.Origin.COOKIES) >= 0) { | 
| cr.dispatchSimpleEvent( | 
| - this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED); | 
| + this, DestinationStore.EventType.DESTINATION_SEARCH_DONE); | 
| + } else { | 
| + this.startLoadCloudDestinations( | 
| + print_preview.Destination.Origin.COOKIES); | 
| } | 
| }, | 
| @@ -564,6 +507,87 @@ cr.define('print_preview', function() { | 
| }, | 
| /** | 
| + * Inserts {@code destination} to the data store and dispatches a | 
| + * DESTINATIONS_INSERTED event. | 
| + * @param {!print_preview.Destination} destination Print destination to | 
| + * insert. | 
| + * @private | 
| + */ | 
| + insertDestination_: function(destination) { | 
| + if (this.insertIntoStore_(destination)) { | 
| + this.destinationsInserted_(destination); | 
| + } | 
| + }, | 
| + | 
| + /** | 
| + * Inserts multiple {@code destinations} to the data store and dispatches | 
| + * single DESTINATIONS_INSERTED event. | 
| + * @param {!Array.<print_preview.Destination>} destinations Print | 
| + * destinations to insert. | 
| + * @private | 
| + */ | 
| + insertDestinations_: function(destinations) { | 
| + var inserted = false; | 
| + destinations.forEach(function(destination) { | 
| + inserted = this.insertIntoStore_(destination) || inserted; | 
| + }, this); | 
| + if (inserted) { | 
| + this.destinationsInserted_(); | 
| + } | 
| + }, | 
| + | 
| + /** | 
| + * Dispatches DESTINATIONS_INSERTED event. In auto select mode, tries to | 
| + * update selected destination to match {@code appState_} settings. | 
| + * @param {print_preview.Destination=} opt_destination The only destination | 
| + * that was changed or skipped if possibly more than one destination was | 
| + * changed. Used as a hint to limit destination search scope in | 
| + * {@code isInAutoSelectMode_). | 
| + */ | 
| + destinationsInserted_: function(opt_destination) { | 
| + cr.dispatchSimpleEvent( | 
| + this, DestinationStore.EventType.DESTINATIONS_INSERTED); | 
| + if (this.isInAutoSelectMode_) { | 
| + var destinationsToSearch = | 
| + opt_destination && [opt_destination] || this.destinations_; | 
| + destinationsToSearch.some(function(destination) { | 
| + if (this.matchPersistedDestination_(destination)) { | 
| + this.selectDestination(destination); | 
| + return true; | 
| + } | 
| + }, this); | 
| + } | 
| + }, | 
| + | 
| + /** | 
| + * Updates an existing print destination with capabilities and display name | 
| + * information. If the destination doesn't already exist, it will be added. | 
| + * @param {!print_preview.Destination} destination Destination to update. | 
| + * @return {!print_preview.Destination} The existing destination that was | 
| + * updated or {@code null} if it was the new destination. | 
| + * @private | 
| + */ | 
| + updateDestination_: function(destination) { | 
| + assert(destination.constructor !== Array, 'Single printer expected'); | 
| + var existingDestination = this.destinationMap_[this.getKey_(destination)]; | 
| + if (existingDestination != null) { | 
| + existingDestination.capabilities = destination.capabilities; | 
| + } else { | 
| + this.insertDestination_(destination); | 
| + } | 
| + | 
| + if (existingDestination == this.selectedDestination_ || | 
| + destination == this.selectedDestination_) { | 
| + this.appState_.persistSelectedDestination(this.selectedDestination_); | 
| + cr.dispatchSimpleEvent( | 
| + this, | 
| + DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); | 
| + } | 
| + | 
| + return existingDestination; | 
| + }, | 
| + | 
| + /** | 
| * Called when the search for Privet printers is done. | 
| * @private | 
| */ | 
| @@ -581,8 +605,8 @@ cr.define('print_preview', function() { | 
| * store. | 
| * @private | 
| */ | 
| - insertDestination_: function(destination) { | 
| - var key = this.getDestinationKey_(destination.origin, destination.id); | 
| + insertIntoStore_: function(destination) { | 
| + var key = this.getKey_(destination); | 
| var existingDestination = this.destinationMap_[key]; | 
| if (existingDestination == null) { | 
| this.destinations_.push(destination); | 
| @@ -628,10 +652,6 @@ cr.define('print_preview', function() { | 
| this.nativeLayer_, | 
| print_preview.NativeLayer.EventType.PRIVET_CAPABILITIES_SET, | 
| this.onPrivetCapabilitiesSet_.bind(this)); | 
| - this.tracker_.add( | 
| - this.userInfo_, | 
| - print_preview.UserInfo.EventType.ACTIVE_USER_CHANGED, | 
| - this.onActiveUserChanged_.bind(this)); | 
| }, | 
| /** | 
| @@ -641,57 +661,34 @@ cr.define('print_preview', function() { | 
| reset_: function() { | 
| this.destinations_ = []; | 
| this.destinationMap_ = {}; | 
| - this.selectedDestination_ = null; | 
| - this.hasLoadedAllCloudDestinations_ = false; | 
| + this.selectDestination(null); | 
| + this.loadedCloudOrigins_ = {}; | 
| this.hasLoadedAllLocalDestinations_ = false; | 
| - this.insertDestination( | 
| + this.insertDestination_( | 
| DestinationStore.createLocalPdfPrintDestination_()); | 
| this.resetAutoSelectTimeout_(); | 
| }, | 
| /** | 
| - * Resets the state of the destination store to its initial state. | 
| - * @private | 
| - */ | 
| - resetCookiesDestinations_: function() { | 
| - // Forget all cookies based destinations. | 
| - this.destinations_ = this.destinations_.filter(function(destination) { | 
| - if (destination.origin == print_preview.Destination.Origin.COOKIES) { | 
| - delete this.destinationMap_[ | 
| - this.getDestinationKey_(destination.origin, destination.id)]; | 
| - return false; | 
| - } | 
| - return true; | 
| - }, this); | 
| - // Reset selected destination, if necessary. | 
| - if (this.selectedDestination_ && | 
| - this.selectedDestination_.origin == | 
| - print_preview.Destination.Origin.COOKIES) { | 
| - this.selectedDestination_ = null; | 
| - } | 
| - this.hasLoadedAllCloudDestinations_ = false; | 
| - this.resetAutoSelectTimeout_(); | 
| - }, | 
| - | 
| - /** | 
| * Resets destination auto selection timeout. | 
| * @private | 
| */ | 
| resetAutoSelectTimeout_: function() { | 
| + this.cancelAutoSelectTimeout_(); | 
| this.autoSelectTimeout_ = | 
| setTimeout(this.onAutoSelectFailed_.bind(this), | 
| DestinationStore.AUTO_SELECT_TIMEOUT_); | 
| }, | 
| /** | 
| - * Called when active user changes. Resets cookie based destinations | 
| - * and starts loading cloud destinations for the active user. | 
| + * Cancels destination auto selection timeout. | 
| * @private | 
| */ | 
| - onActiveUserChanged_: function() { | 
| - this.resetCookiesDestinations_(); | 
| - this.isInAutoSelectMode_ = true; | 
| - this.startLoadCloudDestinations(print_preview.Destination.Origin.COOKIES); | 
| + cancelAutoSelectTimeout_: function() { | 
| + if (this.autoSelectTimeout_ != null) { | 
| + clearTimeout(this.autoSelectTimeout_); | 
| + this.autoSelectTimeout_ = null; | 
| + } | 
| }, | 
| /** | 
| @@ -703,7 +700,7 @@ cr.define('print_preview', function() { | 
| var localDestinations = event.destinationInfos.map(function(destInfo) { | 
| return print_preview.LocalDestinationParser.parse(destInfo); | 
| }); | 
| - this.insertDestinations(localDestinations); | 
| + this.insertDestinations_(localDestinations); | 
| this.isLocalDestinationSearchInProgress_ = false; | 
| cr.dispatchSimpleEvent( | 
| this, DestinationStore.EventType.DESTINATION_SEARCH_DONE); | 
| @@ -720,9 +717,10 @@ cr.define('print_preview', function() { | 
| */ | 
| onLocalDestinationCapabilitiesSet_: function(event) { | 
| var destinationId = event.settingsInfo['printerId']; | 
| - var key = | 
| - this.getDestinationKey_(print_preview.Destination.Origin.LOCAL, | 
| - destinationId); | 
| + var key = this.getDestinationKey_( | 
| + print_preview.Destination.Origin.LOCAL, | 
| + destinationId, | 
| + ''); | 
| var destination = this.destinationMap_[key]; | 
| var capabilities = print_preview.LocalCapabilitiesParser.parse( | 
| event.settingsInfo); | 
| @@ -740,7 +738,7 @@ cr.define('print_preview', function() { | 
| destination = print_preview.LocalDestinationParser.parse( | 
| {deviceName: destinationId, printerName: destinationId}); | 
| destination.capabilities = capabilities; | 
| - this.insertDestination(destination); | 
| + this.insertDestination_(destination); | 
| } | 
| if (this.selectedDestination_ && | 
| this.selectedDestination_.id == destinationId) { | 
| @@ -761,33 +759,28 @@ cr.define('print_preview', function() { | 
| console.error('Failed to get print capabilities for printer ' + | 
| event.destinationId); | 
| if (this.isInAutoSelectMode_ && | 
| - this.matchInitialDestinationStrict_(event.destinationId, | 
| - event.destinationOrigin)) { | 
| - assert(this.destinations_.length > 0, | 
| - 'No destinations were loaded when failed to get initial ' + | 
| - 'destination'); | 
| - this.selectDestination(this.destinations_[0]); | 
| + this.sameAsPersistedDestination_(event.destinationId, | 
| + event.destinationOrigin)) { | 
| + this.selectDefaultDestination_(); | 
| } | 
| }, | 
| /** | 
| - * Called when the /search call completes. Adds the fetched destinations to | 
| - * the destination store. | 
| - * @param {Event} event Contains the fetched destinations. | 
| + * Called when the /search call completes, either successfully or not. | 
| + * In case of success, stores fetched destinations. | 
| + * @param {Event} event Contains the request result. | 
| * @private | 
| */ | 
| onCloudPrintSearchDone_: function(event) { | 
| - this.insertDestinations(event.printers); | 
| - cr.dispatchSimpleEvent( | 
| - this, DestinationStore.EventType.DESTINATION_SEARCH_DONE); | 
| - }, | 
| - | 
| - /** | 
| - * Called when the /search call fails. Updates outstanding request count and | 
| - * dispatches CLOUD_DESTINATIONS_LOADED event. | 
| - * @private | 
| - */ | 
| - onCloudPrintSearchFailed_: function() { | 
| + if (event.printers) { | 
| + this.insertDestinations_(event.printers); | 
| + } | 
| + if (event.searchDone) { | 
| + var origins = this.loadedCloudOrigins_[event.user] || []; | 
| + if (origins.indexOf(event.origin) < 0) { | 
| + this.loadedCloudOrigins_[event.user] = origins.concat([event.origin]); | 
| + } | 
| + } | 
| cr.dispatchSimpleEvent( | 
| this, DestinationStore.EventType.DESTINATION_SEARCH_DONE); | 
| }, | 
| @@ -800,7 +793,7 @@ cr.define('print_preview', function() { | 
| * @private | 
| */ | 
| onCloudPrintPrinterDone_: function(event) { | 
| - this.updateDestination(event.printer); | 
| + this.updateDestination_(event.printer); | 
| }, | 
| /** | 
| @@ -813,13 +806,11 @@ cr.define('print_preview', function() { | 
| */ | 
| onCloudPrintPrinterFailed_: function(event) { | 
| if (this.isInAutoSelectMode_ && | 
| - this.matchInitialDestinationStrict_(event.destinationId, | 
| - event.destinationOrigin)) { | 
| - console.error('Could not find initial printer: ' + event.destinationId); | 
| - assert(this.destinations_.length > 0, | 
| - 'No destinations were loaded when failed to get initial ' + | 
| - 'destination'); | 
| - this.selectDestination(this.destinations_[0]); | 
| + this.sameAsPersistedDestination_(event.destinationId, | 
| + event.destinationOrigin)) { | 
| + console.error( | 
| + 'Failed to fetch last used printer caps: ' + event.destinationId); | 
| + this.selectDefaultDestination_(); | 
| } | 
| }, | 
| @@ -834,7 +825,7 @@ cr.define('print_preview', function() { | 
| this.waitForRegisterDestination_ = null; | 
| this.onDestinationsReload_(); | 
| } else { | 
| - this.insertDestinations( | 
| + this.insertDestinations_( | 
| print_preview.PrivetDestinationParser.parse(event.printer)); | 
| } | 
| }, | 
| @@ -850,7 +841,7 @@ cr.define('print_preview', function() { | 
| print_preview.PrivetDestinationParser.parse(event.printer); | 
| destinations.forEach(function(dest) { | 
| dest.capabilities = event.capabilities; | 
| - this.updateDestination(dest); | 
| + this.updateDestination_(dest); | 
| }, this); | 
| }, | 
| @@ -872,10 +863,8 @@ cr.define('print_preview', function() { | 
| * @private | 
| */ | 
| onAutoSelectFailed_: function() { | 
| - this.autoSelectTimeout_ = null; | 
| - assert(this.destinations_.length > 0, | 
| - 'No destinations were loaded before auto-select timeout expired'); | 
| - this.selectDestination(this.destinations_[0]); | 
| + this.cancelAutoSelectTimeout_(); | 
| + this.selectDefaultDestination_(); | 
| }, | 
| // TODO(vitalybuka): Remove three next functions replacing Destination.id | 
| @@ -883,23 +872,35 @@ cr.define('print_preview', function() { | 
| /** | 
| * Returns key to be used with {@code destinationMap_}. | 
| * @param {!print_preview.Destination.Origin} origin Destination origin. | 
| - * @return {!string} id Destination id. | 
| + * @return {string} id Destination id. | 
| + * @return {string} account User account destination is registered for. | 
| * @private | 
| */ | 
| - getDestinationKey_: function(origin, id) { | 
| - return origin + '/' + id; | 
| + getDestinationKey_: function(origin, id, account) { | 
| + return origin + '/' + id + '/' + account; | 
| }, | 
| /** | 
| - * @param {?string} id Id of the destination. | 
| - * @param {?string} origin Oring of the destination. | 
| - * @return {boolean} Whether a initial destination matches provided. | 
| + * Returns key to be used with {@code destinationMap_}. | 
| + * @param {!print_preview.Destination} destination Destination. | 
| + * @private | 
| + */ | 
| + getKey_: function(destination) { | 
| + return this.getDestinationKey_( | 
| + destination.origin, destination.id, destination.account); | 
| + }, | 
| + | 
| + /** | 
| + * @param {!print_preview.Destination} destination Destination to match. | 
| + * @return {boolean} Whether {@code destination} matches the last user | 
| + * selected one. | 
| * @private | 
| */ | 
| - matchInitialDestination_: function(id, origin) { | 
| - return this.initialDestinationId_ == null || | 
| - this.initialDestinationOrigin_ == null || | 
| - this.matchInitialDestinationStrict_(id, origin); | 
| + matchPersistedDestination_: function(destination) { | 
| + return !this.appState_.selectedDestinationId || | 
| + !this.appState_.selectedDestinationOrigin || | 
| + this.sameAsPersistedDestination_( | 
| + destination.id, destination.origin); | 
| }, | 
| /** | 
| @@ -908,9 +909,9 @@ cr.define('print_preview', function() { | 
| * @return {boolean} Whether destination is the same as initial. | 
| * @private | 
| */ | 
| - matchInitialDestinationStrict_: function(id, origin) { | 
| - return id == this.initialDestinationId_ && | 
| - origin == this.initialDestinationOrigin_; | 
| + sameAsPersistedDestination_: function(id, origin) { | 
| + return id == this.appState_.selectedDestinationId && | 
| + origin == this.appState_.selectedDestinationOrigin; | 
| } | 
| }; |