1 // ========================================================================== 2 // Project: SproutCore - JavaScript Application Framework 3 // Copyright: ©2009 Alex Iskander and TPSi 4 // Portions ©2008-2011 Apple Inc. All rights reserved. 5 // License: Licensed under MIT license (see license.js) 6 // ========================================================================== 7 8 sc_require("mixins/emptiness"); 9 sc_require("mixins/edit_mode"); 10 11 /*globals Forms */ 12 13 /** @class 14 Represents a single row in a form. Rows have label and any number of other child views. 15 16 17 @extends SC.View 18 @author Alex Iskander 19 */ 20 SC.FormRowView = SC.View.extend(SC.FlowedLayout, SC.CalculatesEmptiness, SC.FormsEditMode, 21 /** @scope Forms.FormRowView.prototype */ { 22 classNames: ["sc-form-row-view"], 23 renderDelegateName: 'formRowRenderDelegate', 24 25 flowPadding: SC.propertyFromRenderDelegate('flowPadding'), 26 defaultFlowSpacing: SC.propertyFromRenderDelegate('flowSpacing'), 27 28 fillWidth: YES, 29 layoutDirection: SC.LAYOUT_HORIZONTAL, 30 31 layout: {left: 0, width: 0, height: 0}, 32 33 /** 34 Walks like a duck. 35 */ 36 isFormRow: YES, 37 38 /** 39 A value set so that FormView knows to tell us about the row label size change. 40 */ 41 hasRowLabel: YES, 42 43 44 /** 45 The text to display next to the row. If undefined, SproutCore will try 46 to set it automatically to the key corresponding to this row in the FormView. 47 */ 48 label: undefined, 49 50 /** 51 The actual size for the label, as assigned by the parent FormView. 52 */ 53 rowLabelSize: 0, 54 55 /** 56 The measured size of the label. The parent FormView may use this to 57 determine the proper rowLabelSize. 58 */ 59 rowLabelMeasuredSize: 0, 60 61 /** 62 If NO, the label will not automatically measure itself. The parent 63 FormView normally manages this property for FormRowView. 64 65 Note that FormRowView never changes its own rowLabelSize: it only 66 measures it. The measurement is placed into rowLabelMeasuredSize. 67 68 The FormView then sets the rowLabelSize, which is used to set the 69 width of the LabelView. 70 */ 71 shouldMeasureLabel: YES, 72 73 /** 74 The label view. The default is an SC.FormRowView.LabelView, which is 75 configured to handle resizing. 76 */ 77 labelView: null, // NOTE: gets set at end of file. 78 79 /** 80 Updates keys, content, etc. on fields. Also, handles our "special" field (only-one case) 81 */ 82 createChildViews: function() { 83 // keep array of keys so we can pass on key to child. 84 var cv = SC.clone(this.get('childViews')); 85 86 // add label 87 if (this.labelView.isClass) { 88 this.labelView = this.createChildView(this.labelView, { 89 value: this.get('label') 90 }); 91 92 this.labelView.addObserver('measuredSize', this, 'labelSizeDidChange'); 93 this.labelView.bind('shouldMeasureSize', this, 'shouldMeasureLabel'); 94 this.get('childViews').unshift(this.labelView); 95 } 96 97 var content = this.get('content'); 98 99 sc_super(); 100 101 102 // now, do the actual passing it 103 var idx, len = cv.length, key, v; 104 for (idx = 0; idx < len; idx++) { 105 key = cv[idx]; 106 107 // if the view was originally declared as a string, then we have something to give it 108 if (SC.typeOf(key) === SC.T_STRING) { 109 // try to get the actual view 110 v = this.get(key); 111 112 // see if it does indeed exist, and if it doesn't have a value already 113 if (v && !v.isClass) { 114 if (!v.get('contentValueKey')) { 115 // 116 // NOTE: WE HAVE A SPECIAL CASE 117 // If this is the single field, pass through our formKey 118 // Single-field rows are created by the SC.FormView.row helper. 119 if (key === "_singleField") { 120 v.set('contentValueKey', this.get('formKey')); 121 } else { 122 v.set('contentValueKey', key); 123 } 124 } 125 126 if (!v.get('content')) { 127 v.bind('content', this, 'content') ; 128 } 129 } 130 131 } 132 } 133 134 this.rowLabelSizeDidChange(); 135 }, 136 137 labelDidChange: function() { 138 this.get("labelView").set("value", this.get("label")); 139 }.observes("label"), 140 141 labelSizeDidChange: function() { 142 var size = this.get("labelView").get("measuredSize"); 143 this.set("rowLabelMeasuredSize", size.width); 144 145 // alert parent view if it is a row delegate 146 var pv = this.get("parentView"); 147 if (pv && pv.get("isRowDelegate")) pv.rowLabelMeasuredSizeDidChange(this, size); 148 }, 149 150 rowLabelSizeDidChange: function() { 151 this.get("labelView").adjust({ 152 "width": this.get("rowLabelSize") 153 }); 154 }.observes("rowLabelSize") 155 156 }); 157 158 SC.FormRowView.mixin({ 159 row: function(label, fieldType, ext) { 160 if (label.isClass) { 161 ext = fieldType; 162 fieldType = label; 163 label = null; 164 } 165 // now, create a hash (will be used by the parent form's exampleRow) 166 if (!ext) { 167 ext = {}; 168 } else { 169 ext = SC.clone(ext); 170 } 171 ext.label = label; 172 ext.childViews = ["_singleField"]; 173 ext._singleField = fieldType; 174 return ext; 175 }, 176 177 LabelView: SC.LabelView.extend(SC.AutoResize, SC.CalculatesEmptiness, { 178 shouldAutoResize: NO, // only change the measuredSize so we can update. 179 layout: { left:0, top:0, width: 0, height: 18 }, 180 fillHeight: YES, 181 classNames: ["sc-form-label"], 182 isValue: NO 183 }) 184 }); 185 186 SC.FormRowView.prototype.labelView = SC.FormRowView.LabelView.design(); 187