ticket_item.js revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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.
4
5cr.define('print_preview.ticket_items', function() {
6  'use strict';
7
8  /**
9   * An object that represents a user modifiable item in a print ticket. Each
10   * ticket item has a value which can be set by the user. Ticket items can also
11   * be unavailable for modifying if the print destination doesn't support it or
12   * if other ticket item constraints are not met.
13   * @param {print_preview.AppState=} appState Application state model to update
14   *     when ticket items update.
15   * @param {print_preview.AppState.Field=} field Field of the app state to
16   *     update when ticket item is updated.
17   * @param {print_preview.DestinationStore=} destinationStore Used listen for
18   *     changes in the currently selected destination's capabilities. Since
19   *     this is a common dependency of ticket items, it's handled in the base
20   *     class.
21   * @param {print_preview.DocumentInfo=} documentInfo Used to listen for
22   *     changes in the document. Since this is a common dependency of ticket
23   *     items, it's handled in the base class.
24   * @constructor
25   */
26  function TicketItem(appState, field, destinationStore, documentInfo) {
27    cr.EventTarget.call(this);
28
29    /**
30     * Application state model to update when ticket items update.
31     * @type {print_preview.AppState}
32     * @private
33     */
34    this.appState_ = appState || null;
35
36    /**
37     * Field of the app state to update when ticket item is updated.
38     * @type {print_preview.AppState.Field}
39     * @private
40     */
41    this.field_ = field || null;
42
43    /**
44     * Used listen for changes in the currently selected destination's
45     * capabilities.
46     * @type {print_preview.DestinationStore}
47     * @private
48     */
49    this.destinationStore_ = destinationStore || null;
50
51    /**
52     * Used to listen for changes in the document.
53     * @type {print_preview.DocumentInfo}
54     * @private
55     */
56    this.documentInfo_ = documentInfo || null;
57
58    /**
59     * Backing store of the print ticket item.
60     * @type {Object}
61     * @private
62     */
63    this.value_ = null;
64
65    /**
66     * Keeps track of event listeners for the ticket item.
67     * @type {!EventTracker}
68     * @private
69     */
70    this.tracker_ = new EventTracker();
71
72    this.addEventHandlers_();
73  };
74
75  /**
76   * Event types dispatched by this class.
77   * @enum {string}
78   */
79  TicketItem.EventType = {
80    CHANGE: 'print_preview.ticket_items.TicketItem.CHANGE'
81  };
82
83  TicketItem.prototype = {
84    __proto__: cr.EventTarget.prototype,
85
86    /**
87     * Determines whether a given value is valid for the ticket item.
88     * @param {Object} value The value to check for validity.
89     * @return {boolean} Whether the given value is valid for the ticket item.
90     */
91    wouldValueBeValid: function(value) {
92      throw Error('Abstract method not overridden');
93    },
94
95    /**
96     * @return {boolean} Whether the print destination capability is available.
97     */
98    isCapabilityAvailable: function() {
99      throw Error('Abstract method not overridden');
100    },
101
102    /** @return {!Object} The value of the ticket item. */
103    getValue: function() {
104      if (this.isCapabilityAvailable()) {
105        if (this.value_ == null) {
106          return this.getDefaultValueInternal();
107        } else {
108          return this.value_;
109        }
110      } else {
111        return this.getCapabilityNotAvailableValueInternal();
112      }
113    },
114
115    /** @return {boolean} Whether the ticket item was modified by the user. */
116    isUserEdited: function() {
117      return this.value_ != null;
118    },
119
120    /** @return {boolean} Whether the ticket item's value is valid. */
121    isValid: function() {
122      if (!this.isUserEdited()) {
123        return true;
124      }
125      return this.wouldValueBeValid(this.value_);
126    },
127
128    /**
129     * @param {Object} value Value to compare to the value of this ticket item.
130     * @return {boolean} Whether the given value is equal to the value of the
131     *     ticket item.
132     */
133    isValueEqual: function(value) {
134      return this.getValue() == value;
135    },
136
137    /** @param {!Object} value Value to set as the value of the ticket item. */
138    updateValue: function(value) {
139      // Use comparison with capabilities for event.
140      var sendUpdateEvent = !this.isValueEqual(value);
141      // Don't lose requested value if capability is not available.
142      this.updateValueInternal(value);
143      if (this.appState_) {
144        this.appState_.persistField(this.field_, value);
145      }
146      if (sendUpdateEvent)
147        cr.dispatchSimpleEvent(this, TicketItem.EventType.CHANGE);
148    },
149
150    /**
151     * @return {!Object} Default value of the ticket item if no value was set by
152     *     the user.
153     * @protected
154     */
155    getDefaultValueInternal: function() {
156      throw Error('Abstract method not overridden');
157    },
158
159    /**
160     * @return {!Object} Default value of the ticket item if the capability is
161     *     not available.
162     * @protected
163     */
164    getCapabilityNotAvailableValueInternal: function() {
165      throw Error('Abstract method not overridden');
166    },
167
168    /**
169     * @return {!EventTracker} Event tracker to keep track of events from
170     *     dependencies.
171     * @protected
172     */
173    getTrackerInternal: function() {
174      return this.tracker_;
175    },
176
177    /**
178     * @return {print_preview.Destination} Selected destination from the
179     *     destination store, or {@code null} if no destination is selected.
180     * @protected
181     */
182    getSelectedDestInternal: function() {
183      return this.destinationStore_ ?
184          this.destinationStore_.selectedDestination : null;
185    },
186
187    /**
188     * @return {print_preview.DocumentInfo} Document data model.
189     * @protected
190     */
191    getDocumentInfoInternal: function() {
192      return this.documentInfo_;
193    },
194
195    /**
196     * Dispatches a CHANGE event.
197     * @protected
198     */
199    dispatchChangeEventInternal: function() {
200      cr.dispatchSimpleEvent(
201          this, print_preview.ticket_items.TicketItem.EventType.CHANGE);
202    },
203
204    /**
205     * Updates the value of the ticket item without dispatching any events or
206     * persisting the value.
207     * @protected
208     */
209    updateValueInternal: function(value) {
210      this.value_ = value;
211    },
212
213    /**
214     * Adds event handlers for this class.
215     * @private
216     */
217    addEventHandlers_: function() {
218      if (this.destinationStore_) {
219        this.tracker_.add(
220            this.destinationStore_,
221            print_preview.DestinationStore.EventType.
222                SELECTED_DESTINATION_CAPABILITIES_READY,
223            this.dispatchChangeEventInternal.bind(this));
224      }
225      if (this.documentInfo_) {
226        this.tracker_.add(
227            this.documentInfo_,
228            print_preview.DocumentInfo.EventType.CHANGE,
229            this.dispatchChangeEventInternal.bind(this));
230      }
231    },
232  };
233
234  // Export
235  return {
236    TicketItem: TicketItem
237  };
238});
239