1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr.define('print_preview', function() {
9 * A data store that stores destinations and dispatches events when the data
11 * @param {!print_preview.NativeLayer} nativeLayer Used to fetch local print
13 * @param {!print_preview.AppState} appState Application state.
14 * @param {!print_preview.Metrics} metrics Metrics.
16 * @extends {cr.EventTarget}
18 function DestinationStore(nativeLayer, appState, metrics) {
19 cr.EventTarget.call(this);
22 * Used to fetch local print destinations.
23 * @type {!print_preview.NativeLayer}
26 this.nativeLayer_ = nativeLayer;
29 * Used to load and persist the selected destination.
30 * @type {!print_preview.AppState}
33 this.appState_ = appState;
36 * Used to track metrics.
37 * @type {!print_preview.AppState}
40 this.metrics_ = metrics;
43 * Internal backing store for the data store.
44 * @type {!Array.<!print_preview.Destination>}
47 this.destinations_ = [];
50 * Cache used for constant lookup of destinations by origin and id.
51 * @type {object.<string, !print_preview.Destination>}
54 this.destinationMap_ = {};
57 * Currently selected destination.
58 * @type {print_preview.Destination}
61 this.selectedDestination_ = null;
64 * Initial destination ID used to auto-select the first inserted destination
65 * that matches. If {@code null}, the first destination inserted into the
66 * store will be selected.
70 this.initialDestinationId_ = null;
73 * Initial origin used to auto-select destination.
74 * @type {print_preview.Destination.Origin}
77 this.initialDestinationOrigin_ = print_preview.Destination.Origin.LOCAL;
80 * Whether the destination store will auto select the destination that
81 * matches the initial destination.
85 this.isInAutoSelectMode_ = false;
88 * Event tracker used to track event listeners of the destination store.
89 * @type {!EventTracker}
92 this.tracker_ = new EventTracker();
95 * Used to fetch cloud-based print destinations.
96 * @type {print_preview.CloudPrintInterface}
99 this.cloudPrintInterface_ = null;
102 * Whether the destination store has already loaded or is loading all cloud
107 this.hasLoadedAllCloudDestinations_ = false;
110 * ID of a timeout after the initial destination ID is set. If no inserted
111 * destination matches the initial destination ID after the specified
112 * timeout, the first destination in the store will be automatically
117 this.autoSelectTimeout_ = null;
120 * Whether a search for local destinations is in progress.
124 this.isLocalDestinationSearchInProgress_ = false;
127 * Whether the destination store has already loaded or is loading all local
132 this.hasLoadedAllLocalDestinations_ = false;
135 * Whether a search for privet destinations is in progress.
139 this.isPrivetDestinationSearchInProgress_ = false;
142 * Whether the destination store has already loaded or is loading all privet
147 this.hasLoadedAllPrivetDestinations_ = false;
150 * ID of a timeout after the start of a privet search to end that privet
155 this.privetSearchTimeout_ = null;
158 * Map set of IDs of privet register promo destinations click.
159 * @type {!Object.<string, bool>}
162 this.waitForRegisterDestination_ = null;
164 this.addEventListeners_();
169 * Event types dispatched by the data store.
172 DestinationStore.EventType = {
173 DESTINATION_SEARCH_DONE:
174 'print_preview.DestinationStore.DESTINATION_SEARCH_DONE',
175 DESTINATION_SEARCH_STARTED:
176 'print_preview.DestinationStore.DESTINATION_SEARCH_STARTED',
177 DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT',
178 DESTINATIONS_INSERTED:
179 'print_preview.DestinationStore.DESTINATIONS_INSERTED',
180 CACHED_SELECTED_DESTINATION_INFO_READY:
181 'print_preview.DestinationStore.CACHED_SELECTED_DESTINATION_INFO_READY',
182 SELECTED_DESTINATION_CAPABILITIES_READY:
183 'print_preview.DestinationStore.SELECTED_DESTINATION_CAPABILITIES_READY'
187 * Delay in milliseconds before the destination store ignores the initial
188 * destination ID and just selects any printer (since the initial destination
194 DestinationStore.AUTO_SELECT_TIMEOUT_ = 15000;
197 * Amount of time spent searching for privet destination, in milliseconds.
202 DestinationStore.PRIVET_SEARCH_DURATION_ = 2000;
205 * Creates a local PDF print destination.
206 * @return {!print_preview.Destination} Created print destination.
209 DestinationStore.createLocalPdfPrintDestination_ = function() {
210 var dest = new print_preview.Destination(
211 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
212 print_preview.Destination.Type.LOCAL,
213 print_preview.Destination.Origin.LOCAL,
214 localStrings.getString('printToPDF'),
216 print_preview.Destination.ConnectionStatus.ONLINE);
217 dest.capabilities = {
222 {type: 'AUTO', is_default: true},
227 color: { option: [{type: 'STANDARD_COLOR', is_default: true}] }
233 DestinationStore.prototype = {
234 __proto__: cr.EventTarget.prototype,
237 * @return {!Array.<!print_preview.Destination>} List of destinations in
241 return this.destinations_.slice(0);
245 * @return {print_preview.Destination} The currently selected destination or
246 * {@code null} if none is selected.
248 get selectedDestination() {
249 return this.selectedDestination_;
253 * @return {boolean} Whether a search for local destinations is in progress.
255 get isLocalDestinationSearchInProgress() {
256 return this.isLocalDestinationSearchInProgress_ ||
257 this.isPrivetDestinationSearchInProgress_;
261 * @return {boolean} Whether a search for cloud destinations is in progress.
263 get isCloudDestinationSearchInProgress() {
264 return this.cloudPrintInterface_ &&
265 this.cloudPrintInterface_.isCloudDestinationSearchInProgress;
269 * Initializes the destination store. Sets the initially selected
270 * destination. If any inserted destinations match this ID, that destination
271 * will be automatically selected. This method must be called after the
272 * print_preview.AppState has been initialized.
273 * @param {?string} systemDefaultDestinationId ID of the system default
277 init: function(systemDefaultDestinationId) {
278 if (this.appState_.selectedDestinationId &&
279 this.appState_.selectedDestinationOrigin) {
280 this.initialDestinationId_ = this.appState_.selectedDestinationId;
281 this.initialDestinationOrigin_ =
282 this.appState_.selectedDestinationOrigin;
283 } else if (systemDefaultDestinationId) {
284 this.initialDestinationId_ = systemDefaultDestinationId;
285 this.initialDestinationOrigin_ = print_preview.Destination.Origin.LOCAL;
287 this.isInAutoSelectMode_ = true;
288 if (!this.initialDestinationId_ || !this.initialDestinationOrigin_) {
289 this.onAutoSelectFailed_();
291 var key = this.getDestinationKey_(this.initialDestinationOrigin_,
292 this.initialDestinationId_);
293 var candidate = this.destinationMap_[key];
294 if (candidate != null) {
295 this.selectDestination(candidate);
296 } else if (this.initialDestinationOrigin_ ==
297 print_preview.Destination.Origin.LOCAL) {
298 this.nativeLayer_.startGetLocalDestinationCapabilities(
299 this.initialDestinationId_);
300 } else if (this.cloudPrintInterface_ &&
301 (this.initialDestinationOrigin_ ==
302 print_preview.Destination.Origin.COOKIES ||
303 this.initialDestinationOrigin_ ==
304 print_preview.Destination.Origin.DEVICE)) {
305 this.cloudPrintInterface_.printer(this.initialDestinationId_,
306 this.initialDestinationOrigin_);
307 } else if (this.initialDestinationOrigin_ ==
308 print_preview.Destination.Origin.PRIVET) {
309 // TODO(noamsml): Resolve a specific printer instead of listing all
310 // privet printers in this case.
311 this.nativeLayer_.startGetPrivetDestinations();
313 var destinationName = this.appState_.selectedDestinationName || '';
315 // Create a fake selectedDestination_ that is not actually in the
316 // destination store. When the real destination is created, this
317 // destination will be overwritten.
318 this.selectedDestination_ = new print_preview.Destination(
319 this.initialDestinationId_,
320 print_preview.Destination.Type.LOCAL,
321 print_preview.Destination.Origin.PRIVET,
324 print_preview.Destination.ConnectionStatus.ONLINE);
325 this.selectedDestination_.capabilities =
326 this.appState_.selectedDestinationCapabilities;
328 cr.dispatchSimpleEvent(
330 DestinationStore.EventType.CACHED_SELECTED_DESTINATION_INFO_READY);
333 this.onAutoSelectFailed_();
339 * Sets the destination store's Google Cloud Print interface.
340 * @param {!print_preview.CloudPrintInterface} cloudPrintInterface Interface
343 setCloudPrintInterface: function(cloudPrintInterface) {
344 this.cloudPrintInterface_ = cloudPrintInterface;
346 this.cloudPrintInterface_,
347 cloudprint.CloudPrintInterface.EventType.SEARCH_DONE,
348 this.onCloudPrintSearchDone_.bind(this));
350 this.cloudPrintInterface_,
351 cloudprint.CloudPrintInterface.EventType.SEARCH_FAILED,
352 this.onCloudPrintSearchFailed_.bind(this));
354 this.cloudPrintInterface_,
355 cloudprint.CloudPrintInterface.EventType.PRINTER_DONE,
356 this.onCloudPrintPrinterDone_.bind(this));
358 this.cloudPrintInterface_,
359 cloudprint.CloudPrintInterface.EventType.PRINTER_FAILED,
360 this.onCloudPrintPrinterFailed_.bind(this));
364 * @return {boolean} Whether only default cloud destinations have been
367 hasOnlyDefaultCloudDestinations: function() {
368 return this.destinations_.every(function(dest) {
369 return dest.isLocal ||
370 dest.id == print_preview.Destination.GooglePromotedId.DOCS ||
371 dest.id == print_preview.Destination.GooglePromotedId.FEDEX;
375 /** @param {!print_preview.Destination} Destination to select. */
376 selectDestination: function(destination) {
377 this.selectedDestination_ = destination;
378 this.selectedDestination_.isRecent = true;
379 this.isInAutoSelectMode_ = false;
380 if (this.autoSelectTimeout_ != null) {
381 clearTimeout(this.autoSelectTimeout_);
382 this.autoSelectTimeout_ = null;
384 if (destination.id == print_preview.Destination.GooglePromotedId.FEDEX &&
385 !destination.isTosAccepted) {
386 assert(this.cloudPrintInterface_ != null,
387 'Selected FedEx Office destination, but Google Cloud Print is ' +
389 destination.isTosAccepted = true;
390 this.cloudPrintInterface_.updatePrinterTosAcceptance(destination.id,
394 this.appState_.persistSelectedDestination(this.selectedDestination_);
396 if (destination.cloudID &&
397 this.destinations.some(function(otherDestination) {
398 return otherDestination.cloudID == destination.cloudID &&
399 otherDestination != destination;
401 if (destination.isPrivet) {
402 this.metrics_.incrementDestinationSearchBucket(
403 print_preview.Metrics.DestinationSearchBucket.
404 PRIVET_DUPLICATE_SELECTED);
406 this.metrics_.incrementDestinationSearchBucket(
407 print_preview.Metrics.DestinationSearchBucket.
408 CLOUD_DUPLICATE_SELECTED);
412 cr.dispatchSimpleEvent(
413 this, DestinationStore.EventType.DESTINATION_SELECT);
414 if (destination.capabilities == null) {
415 if (destination.isPrivet) {
416 this.nativeLayer_.startGetPrivetDestinationCapabilities(
419 else if (destination.isLocal) {
420 this.nativeLayer_.startGetLocalDestinationCapabilities(
423 assert(this.cloudPrintInterface_ != null,
424 'Selected destination is a cloud destination, but Google ' +
425 'Cloud Print is not enabled');
426 this.cloudPrintInterface_.printer(destination.id,
430 cr.dispatchSimpleEvent(
432 DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
437 * Inserts a print destination to the data store and dispatches a
438 * DESTINATIONS_INSERTED event. If the destination matches the initial
439 * destination ID, then the destination will be automatically selected.
440 * @param {!print_preview.Destination} destination Print destination to
443 insertDestination: function(destination) {
444 if (this.insertDestination_(destination)) {
445 cr.dispatchSimpleEvent(
446 this, DestinationStore.EventType.DESTINATIONS_INSERTED);
447 if (this.isInAutoSelectMode_ &&
448 this.matchInitialDestination_(destination.id, destination.origin)) {
449 this.selectDestination(destination);
455 * Inserts multiple print destinations to the data store and dispatches one
456 * DESTINATIONS_INSERTED event. If any of the destinations match the initial
457 * destination ID, then that destination will be automatically selected.
458 * @param {!Array.<print_preview.Destination>} destinations Print
459 * destinations to insert.
461 insertDestinations: function(destinations) {
462 var insertedDestination = false;
463 var destinationToAutoSelect = null;
464 destinations.forEach(function(dest) {
465 if (this.insertDestination_(dest)) {
466 insertedDestination = true;
467 if (this.isInAutoSelectMode_ &&
468 destinationToAutoSelect == null &&
469 this.matchInitialDestination_(dest.id, dest.origin)) {
470 destinationToAutoSelect = dest;
474 if (insertedDestination) {
475 cr.dispatchSimpleEvent(
476 this, DestinationStore.EventType.DESTINATIONS_INSERTED);
478 if (destinationToAutoSelect != null) {
479 this.selectDestination(destinationToAutoSelect);
484 * Updates an existing print destination with capabilities and display name
485 * information. If the destination doesn't already exist, it will be added.
486 * @param {!print_preview.Destination} destination Destination to update.
487 * @return {!print_preview.Destination} The existing destination that was
488 * updated or {@code null} if it was the new destination.
490 updateDestination: function(destination) {
491 assert(destination.constructor !== Array, 'Single printer expected');
492 var key = this.getDestinationKey_(destination.origin, destination.id);
493 var existingDestination = this.destinationMap_[key];
494 if (existingDestination != null) {
495 existingDestination.capabilities = destination.capabilities;
497 this.insertDestination(destination);
500 if (existingDestination == this.selectedDestination_ ||
501 destination == this.selectedDestination_) {
502 this.appState_.persistSelectedDestination(this.selectedDestination_);
503 cr.dispatchSimpleEvent(
505 DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
508 return existingDestination;
511 /** Initiates loading of local print destinations. */
512 startLoadLocalDestinations: function() {
513 if (!this.hasLoadedAllLocalDestinations_) {
514 this.hasLoadedAllLocalDestinations_ = true;
515 this.nativeLayer_.startGetLocalDestinations();
516 this.isLocalDestinationSearchInProgress_ = true;
517 cr.dispatchSimpleEvent(
518 this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED);
522 /** Initiates loading of privet print destinations. */
523 startLoadPrivetDestinations: function() {
524 if (!this.hasLoadedAllPrivetDestinations_) {
525 this.isPrivetDestinationSearchInProgress_ = true;
526 this.nativeLayer_.startGetPrivetDestinations();
527 cr.dispatchSimpleEvent(
528 this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED);
529 this.privetSearchTimeout_ = setTimeout(
530 this.endPrivetPrinterSearch_.bind(this),
531 DestinationStore.PRIVET_SEARCH_DURATION_);
536 * Initiates loading of cloud destinations.
538 startLoadCloudDestinations: function() {
539 if (this.cloudPrintInterface_ != null &&
540 !this.hasLoadedAllCloudDestinations_) {
541 this.hasLoadedAllCloudDestinations_ = true;
542 this.cloudPrintInterface_.search(true);
543 this.cloudPrintInterface_.search(false);
544 cr.dispatchSimpleEvent(
545 this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED);
550 * Wait for a privet device to be registered.
552 waitForRegister: function(id) {
553 this.nativeLayer_.startGetPrivetDestinations();
554 this.waitForRegisterDestination_ = id;
558 * Called when the search for Privet printers is done.
561 endPrivetPrinterSearch_: function() {
562 this.nativeLayer_.stopGetPrivetDestinations();
563 this.isPrivetDestinationSearchInProgress_ = false;
564 this.hasLoadedAllPrivetDestinations_ = true;
565 cr.dispatchSimpleEvent(
566 this, DestinationStore.EventType.DESTINATION_SEARCH_DONE);
571 * Inserts a destination into the store without dispatching any events.
572 * @return {boolean} Whether the inserted destination was not already in the
576 insertDestination_: function(destination) {
577 var key = this.getDestinationKey_(destination.origin, destination.id);
578 var existingDestination = this.destinationMap_[key];
579 if (existingDestination == null) {
580 this.destinations_.push(destination);
581 this.destinationMap_[key] = destination;
583 } else if (existingDestination.connectionStatus ==
584 print_preview.Destination.ConnectionStatus.UNKNOWN &&
585 destination.connectionStatus !=
586 print_preview.Destination.ConnectionStatus.UNKNOWN) {
587 existingDestination.connectionStatus = destination.connectionStatus;
595 * Binds handlers to events.
598 addEventListeners_: function() {
601 print_preview.NativeLayer.EventType.LOCAL_DESTINATIONS_SET,
602 this.onLocalDestinationsSet_.bind(this));
605 print_preview.NativeLayer.EventType.CAPABILITIES_SET,
606 this.onLocalDestinationCapabilitiesSet_.bind(this));
609 print_preview.NativeLayer.EventType.GET_CAPABILITIES_FAIL,
610 this.onGetCapabilitiesFail_.bind(this));
613 print_preview.NativeLayer.EventType.DESTINATIONS_RELOAD,
614 this.onDestinationsReload_.bind(this));
617 print_preview.NativeLayer.EventType.PRIVET_PRINTER_CHANGED,
618 this.onPrivetPrinterAdded_.bind(this));
621 print_preview.NativeLayer.EventType.PRIVET_CAPABILITIES_SET,
622 this.onPrivetCapabilitiesSet_.bind(this));
626 * Resets the state of the destination store to its initial state.
630 this.destinations_ = [];
631 this.destinationMap_ = {};
632 this.selectedDestination_ = null;
633 this.hasLoadedAllCloudDestinations_ = false;
634 this.hasLoadedAllLocalDestinations_ = false;
635 this.insertDestination(
636 DestinationStore.createLocalPdfPrintDestination_());
637 this.autoSelectTimeout_ =
638 setTimeout(this.onAutoSelectFailed_.bind(this),
639 DestinationStore.AUTO_SELECT_TIMEOUT_);
643 * Called when the local destinations have been got from the native layer.
644 * @param {Event} Contains the local destinations.
647 onLocalDestinationsSet_: function(event) {
648 var localDestinations = event.destinationInfos.map(function(destInfo) {
649 return print_preview.LocalDestinationParser.parse(destInfo);
651 this.insertDestinations(localDestinations);
652 this.isLocalDestinationSearchInProgress_ = false;
653 cr.dispatchSimpleEvent(
654 this, DestinationStore.EventType.DESTINATION_SEARCH_DONE);
658 * Called when the native layer retrieves the capabilities for the selected
659 * local destination. Updates the destination with new capabilities if the
660 * destination already exists, otherwise it creates a new destination and
661 * then updates its capabilities.
662 * @param {Event} event Contains the capabilities of the local print
666 onLocalDestinationCapabilitiesSet_: function(event) {
667 var destinationId = event.settingsInfo['printerId'];
669 this.getDestinationKey_(print_preview.Destination.Origin.LOCAL,
671 var destination = this.destinationMap_[key];
672 var capabilities = print_preview.LocalCapabilitiesParser.parse(
675 // In case there were multiple capabilities request for this local
676 // destination, just ignore the later ones.
677 if (destination.capabilities != null) {
680 destination.capabilities = capabilities;
682 // TODO(rltoscano): This makes the assumption that the "deviceName" is
683 // the same as "printerName". We should include the "printerName" in the
684 // response. See http://crbug.com/132831.
685 destination = print_preview.LocalDestinationParser.parse(
686 {deviceName: destinationId, printerName: destinationId});
687 destination.capabilities = capabilities;
688 this.insertDestination(destination);
690 if (this.selectedDestination_ &&
691 this.selectedDestination_.id == destinationId) {
692 cr.dispatchSimpleEvent(this,
693 DestinationStore.EventType.
694 SELECTED_DESTINATION_CAPABILITIES_READY);
699 * Called when a request to get a local destination's print capabilities
700 * fails. If the destination is the initial destination, auto-select another
701 * destination instead.
702 * @param {Event} event Contains the destination ID that failed.
705 onGetCapabilitiesFail_: function(event) {
706 console.error('Failed to get print capabilities for printer ' +
707 event.destinationId);
708 if (this.isInAutoSelectMode_ &&
709 this.matchInitialDestinationStrict_(event.destinationId,
710 event.destinationOrigin)) {
711 assert(this.destinations_.length > 0,
712 'No destinations were loaded when failed to get initial ' +
714 this.selectDestination(this.destinations_[0]);
719 * Called when the /search call completes. Adds the fetched destinations to
720 * the destination store.
721 * @param {Event} event Contains the fetched destinations.
724 onCloudPrintSearchDone_: function(event) {
725 this.insertDestinations(event.printers);
726 cr.dispatchSimpleEvent(
727 this, DestinationStore.EventType.DESTINATION_SEARCH_DONE);
731 * Called when the /search call fails. Updates outstanding request count and
732 * dispatches CLOUD_DESTINATIONS_LOADED event.
735 onCloudPrintSearchFailed_: function() {
736 cr.dispatchSimpleEvent(
737 this, DestinationStore.EventType.DESTINATION_SEARCH_DONE);
741 * Called when /printer call completes. Updates the specified destination's
742 * print capabilities.
743 * @param {Event} event Contains detailed information about the
747 onCloudPrintPrinterDone_: function(event) {
748 this.updateDestination(event.printer);
752 * Called when the Google Cloud Print interface fails to lookup a
753 * destination. Selects another destination if the failed destination was
754 * the initial destination.
755 * @param {object} event Contains the ID of the destination that was failed
759 onCloudPrintPrinterFailed_: function(event) {
760 if (this.isInAutoSelectMode_ &&
761 this.matchInitialDestinationStrict_(event.destinationId,
762 event.destinationOrigin)) {
763 console.error('Could not find initial printer: ' + event.destinationId);
764 assert(this.destinations_.length > 0,
765 'No destinations were loaded when failed to get initial ' +
767 this.selectDestination(this.destinations_[0]);
772 * Called when a Privet printer is added to the local network.
773 * @param {object} event Contains information about the added printer.
776 onPrivetPrinterAdded_: function(event) {
777 if (event.printer.serviceName == this.waitForRegisterDestination_ &&
778 !event.printer.isUnregistered) {
779 this.waitForRegisterDestination_ = null;
780 this.onDestinationsReload_();
782 this.insertDestinations(
783 print_preview.PrivetDestinationParser.parse(event.printer));
788 * Called when capabilities for a privet printer are set.
789 * @param {object} event Contains the capabilities and printer ID.
792 onPrivetCapabilitiesSet_: function(event) {
793 var destinationId = event.printerId;
795 print_preview.PrivetDestinationParser.parse(event.printer);
796 destinations.forEach(function(dest) {
797 dest.capabilities = event.capabilities;
798 this.updateDestination(dest);
803 * Called from native layer after the user was requested to sign in, and did
807 onDestinationsReload_: function() {
809 this.isInAutoSelectMode_ = true;
810 this.startLoadLocalDestinations();
811 this.startLoadCloudDestinations();
812 this.startLoadPrivetDestinations();
816 * Called when auto-selection fails. Selects the first destination in store.
819 onAutoSelectFailed_: function() {
820 this.autoSelectTimeout_ = null;
821 assert(this.destinations_.length > 0,
822 'No destinations were loaded before auto-select timeout expired');
823 this.selectDestination(this.destinations_[0]);
826 // TODO(vitalybuka): Remove three next functions replacing Destination.id
827 // and Destination.origin by complex ID.
829 * Returns key to be used with {@code destinationMap_}.
830 * @param {!print_preview.Destination.Origin} origin Destination origin.
831 * @return {!string} id Destination id.
834 getDestinationKey_: function(origin, id) {
835 return origin + '/' + id;
839 * @param {?string} id Id of the destination.
840 * @param {?string} origin Oring of the destination.
841 * @return {boolean} Whether a initial destination matches provided.
844 matchInitialDestination_: function(id, origin) {
845 return this.initialDestinationId_ == null ||
846 this.initialDestinationOrigin_ == null ||
847 this.matchInitialDestinationStrict_(id, origin);
851 * @param {?string} id Id of the destination.
852 * @param {?string} origin Oring of the destination.
853 * @return {boolean} Whether destination is the same as initial.
856 matchInitialDestinationStrict_: function(id, origin) {
857 return id == this.initialDestinationId_ &&
858 origin == this.initialDestinationOrigin_;
864 DestinationStore: DestinationStore