1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 sc_require('render_delegates/render_delegate');
  9 
 10 SC.RenderDelegate.reopen({
 11   /**
 12     A list of size names to look for when automatically determining
 13     control size. By default, this has all of the SproutCore control sizes.
 14   */
 15   sizes: [
 16     SC.TINY_CONTROL_SIZE, SC.SMALL_CONTROL_SIZE,
 17     SC.REGULAR_CONTROL_SIZE, SC.LARGE_CONTROL_SIZE,
 18     SC.HUGE_CONTROL_SIZE, SC.JUMBO_CONTROL_SIZE
 19   ],
 20 
 21   /**
 22     Determines the correct size for the given data source, and returns the
 23     hash, if any, representing it.
 24    
 25     The hashes to choose from are properties on the render delegate. You define
 26     them with the same name as you would use for styling. For example,
 27     SC.REGULAR_CONTROL_SIZE uses a property name 'sc-regular-size':
 28    
 29         SC.RenderDelegate.create({
 30           'sc-regular-size': {
 31             // my properties here
 32           }
 33    
 34     If no matching size is found, the hash (if any) for SC.REGULAR_CONTROL_SIZE
 35     will be returned.
 36    
 37     @param {DataSource} dataSource The data source in which to find `controlSize`
 38     or `frame` and to determine the size for.
 39    
 40     @returns {Hash undefined}
 41   */
 42   sizeFor: function(dataSource) {
 43     var controlSize = dataSource.get('controlSize'), size, idx, len;
 44 
 45     // if there is a control size set on the control
 46     // then we need to use it, and give an error if we
 47     // don't have it.
 48     if (controlSize) {
 49       if (!this[controlSize]) {
 50         // create a hash for the control size
 51         this[controlSize] = {};
 52       }
 53 
 54       size = this[controlSize];
 55 
 56       // make sure there's a name on the size for use as class name
 57       if (!size.name) {
 58         size.name = controlSize;
 59       }
 60 
 61       return size;
 62     }
 63 
 64     // try to determine control size for the supplied frame
 65     // TODO: cache this in dataSource.renderState
 66     var frame = dataSource.get('frame');
 67     if (!frame) {
 68       size = this['sc-regular-size'];
 69 
 70       // create the size hash if needed
 71       if (!size) { size = this['sc-regular-size'] = {}; }
 72       if (!size.name) { size.name = 'sc-regular-size'; }
 73       return size;
 74     }
 75 
 76     // loop to automatically find size
 77     for (idx = 0; idx < len; idx++) {
 78       key = sizes[idx];
 79       size = this[key];
 80 
 81       // when the size is not defined, skip it.
 82       if (!size) {
 83         continue;
 84       }
 85 
 86       if (
 87         // if no auto-size-selection params are supplied, then we cannot
 88         // automatically select a size...
 89         (
 90           size.width === undefined && size.height === undefined && 
 91           size.minHeight === undefined && size.minWidth === undefined &&
 92           size.maxHeight === undefined && size.maxWidth === undefined
 93         ) ||
 94 
 95         // otherwise, if any are defined and are non-equal
 96         (size.width !== undefined && frame.width !== size.width) ||
 97         (size.minWidth !== undefined && frame.width < size.minWidth) ||
 98         (size.maxWidth !== undefined && frame.width > size.maxWidth) ||
 99 
100         (size.height !== undefined && frame.height !== size.height) ||
101         (size.minHeight !== undefined && frame.height < size.minHeight) ||
102         (size.maxHeight !== undefined && frame.height < size.maxHeight)
103       ) {
104         continue;
105       }
106 
107       // the size needs a name to use as a class name. If one is not already
108       // present, set it to the key.
109       if (!size.name) {
110         size.name = key;
111       }
112 
113       return size;
114     }
115 
116     // hardcoded to return regular size if defined
117     size = this['sc-regular-size'];
118 
119     // create the size hash if needed
120     if (!size) { size = this['sc-regular-size'] = {}; }
121     if (!size.name) { size.name = 'sc-regular-size'; }
122 
123 
124     return size;
125   },
126 
127   /**
128     Determines the proper size for the dataSource, and then renders the class
129     name corresponding to that size.
130   */
131   addSizeClassName: function(dataSource, context) {
132     var size = this.sizeFor(dataSource);
133     if (size) {
134       context.addClass(size.name);
135     }
136   },
137 
138   /**
139     Determines the proper size for the dataSource, and then updates
140     the DOM to include that size's class name.
141   */
142   updateSizeClassName: function(dataSource, jquery) {
143     var size = this.sizeFor(dataSource);
144     if (size) {
145       jquery.addClass(size.name);
146     }
147   },
148 
149   /**
150     Retrieves the given property for the specified data source. This property
151     may be static, or may be computed specifically for this data source. This
152     version fo `getPropertyFor` will check in your size hashes to see if any
153     properties have been overridden.
154     
155     @param {DataSource} dataSource The data source to get the property
156     for. Some properties may differ based on the data source; for instance,
157     some may have different values depending on size.
158     @param {String} propertyName The name of the property to retrieve.
159   */
160   getPropertyFor: function(dataSource, propertyName) {
161     var size = this.sizeFor(dataSource);
162     if (size) {
163       if (size[propertyName + 'For']) {
164         return size[propertyName + 'For'](dataSource, propertyName);
165       } else if (size[propertyName] !== undefined) {
166         return size[propertyName];
167       }
168     }
169 
170     if (this[propertyName + 'For']) {
171       return this[propertyName + 'For'];
172     }
173 
174     return this[propertyName];
175   }
176 });
177