1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 
  9 /**
 10   @class
 11 
 12   Displays a progress bar.  You can display both a defined and an
 13   indeterminate progressbar.  The progress bar itself is designed to be styled
 14   using CSS classes with the following structure:
 15 
 16       <div class="sc-progress-view"><div class="inner"></div></div>
 17 
 18   The outer can form the boundary of the bar while the inner will be adjusted
 19   to fit the percentage of the progress.
 20 
 21   Creating a ProgressView accepts a number of properties, for example:
 22 
 23       progressView: SC.ProgressView.design({
 24         value: 50,
 25         minimum: 0,
 26         maximum: 100,
 27         isIndeterminate: NO,
 28         isEnabled: YES
 29       })
 30 
 31   @extends SC.View
 32   @extends SC.Control
 33   @since SproutCore 1.0
 34 */
 35 SC.ProgressView = SC.View.extend(SC.Control,
 36 /** @scope SC.ProgressView.prototype */{
 37 
 38   /**
 39     @type Array
 40     @default ['sc-progress-view']
 41     @see SC.View#classNames
 42   */
 43   classNames: ['sc-progress-view'],
 44 
 45   /**
 46     @type Array
 47     @default ['displayValue', 'ariaValue', 'minimum', 'maximum', 'isIndeterminate', 'isRunning', 'isVisibleInWindow']
 48     @see SC.View#displayProperties
 49   */
 50   displayProperties: ['displayValue', 'ariaValue', 'minimum', 'maximum', 'isIndeterminate', 'isRunning', 'isVisibleInWindow'],
 51 
 52   /**
 53     @type String
 54     @default 'progressRenderDelegate'
 55   */
 56   renderDelegateName: 'progressRenderDelegate',
 57 
 58   // ........................................
 59   // PROPERTIES
 60   //
 61 
 62   /**
 63     Bind this to the current value of the progress bar.  Note that by default
 64     an empty value will disable the progress bar and a multiple value will make
 65     it indeterminate.
 66 
 67     @type Number
 68     @default 0.50
 69   */
 70   value: 0.50,
 71 
 72   /** @private */
 73   valueBindingDefault: SC.Binding.single().notEmpty(),
 74 
 75   /**
 76     @field
 77     @type Number
 78     @observes value
 79     @observes maximum
 80     @observes minimum
 81   */
 82   displayValue: function(){
 83     var minimum = this.get('minimum') || 0.0,
 84         maximum = this.get('maximum') || 1.0,
 85         value = this.get('value') || 0.0;
 86 
 87     // Percent value.
 88     value = (value - minimum) / (maximum - minimum);
 89 
 90     if (isNaN(value)) value = 0.0;
 91     // cannot be smaller then minimum
 92     if (value < 0.0) value = 0.0;
 93     // cannot be larger then maximum
 94     if (value > 1.0) value = 1.0;
 95 
 96     return value;
 97   }.property('value', 'maximum', 'minimum').cacheable(),
 98 
 99   /**
100     The WAI-ARIA role for progress view.
101 
102     @type String
103     @default 'progressbar'
104     @readOnly
105   */
106   ariaRole: 'progressbar',
107 
108   /**
109     The WAI-ARIA value for the progress view. This value will be passed to any
110     rendering code as-is, not converted into percentages, etc. It is computed
111     based on the original value property.
112 
113     @property
114   */
115   ariaValue: function() {
116     return this.get('value');
117   }.property('value').cacheable(),
118 
119   /**
120     The minimum value of the progress.
121 
122     @type Number
123     @default 0
124   */
125   minimum: 0,
126 
127   /** @private */
128   minimumBindingDefault: SC.Binding.single().notEmpty(),
129 
130   /**
131     Optionally specify the key used to extract the minimum progress value
132     from the content object.  If this is set to null then the minimum value
133     will not be derived from the content object.
134 
135     @type String
136     @default null
137   */
138   contentMinimumKey: null,
139 
140   /**
141     The maximum value of the progress bar.
142 
143     @type Number
144     @default 1.0
145   */
146   maximum: 1.0,
147 
148   /** @private */
149   maximumBindingDefault: SC.Binding.single().notEmpty(),
150 
151   /**
152     Optionally specify the key used to extract the maximum progress value
153     from the content object.  If this is set to null then the maximum value
154     will not be derived from the content object.
155 
156     @type String
157     @default null
158   */
159   contentMaximumKey: null,
160 
161   /**
162     Set to true if the item in progress is indeterminate.  This may be
163     overridden by the actual value.
164 
165     @type Boolean
166     @default NO
167   */
168   isIndeterminate: NO,
169 
170   /** @private */
171   isIndeterminateBindingDefault: SC.Binding.bool(),
172 
173   /**
174     Set to YES when the process is currently running.  This will cause the
175     progress bar to animate, especially if it is indeterminate.
176 
177     @type Boolean
178     @default NO
179   */
180   isRunning: NO,
181 
182   /** @private */
183   isRunningBindingDefault: SC.Binding.bool(),
184 
185   /**
186     Optionally specify the key used to extract the isIndeterminate value
187     from the content object.  If this is set to null then the isIndeterminate
188     value will not be derived from the content object.
189 
190     @type String
191     @default null
192   */
193   contentIsIndeterminateKey: null,
194 
195   // ........................................
196   // INTERNAL SUPPORT
197   //
198 
199   /** @private */
200   contentPropertyDidChange: function(target, key) {
201     var content = this.get('content');
202     this.beginPropertyChanges()
203       .updatePropertyFromContent('value', key, 'contentValueKey', content)
204       .updatePropertyFromContent('minimum', key, 'contentMinimumKey', content)
205       .updatePropertyFromContent('maximum', key, 'contentMaximumKey', content)
206       .updatePropertyFromContent('isIndeterminate', key, 'contentIsIndeterminateKey', content)
207     .endPropertyChanges();
208   },
209 
210   /** @private */
211   didCreateLayer: function() {
212     // When using the JavaScript animation, we cannot start until the layer is
213     // created.  Then if we are indeterminate, running and visible in the
214     // window already, start animating.
215     if (this.get('isIndeterminate') && this.get('isRunning') && this.get('isVisibleInWindow')) {
216       this.displayDidChange();
217     }
218   }
219 
220 });
221 
222