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 sc_require('views/segmented'); 9 10 /** 11 @static 12 @type String 13 @constant 14 */ 15 SC.TOP_LOCATION = 'top'; 16 17 /** 18 @static 19 @type String 20 @constant 21 */ 22 SC.TOP_TOOLBAR_LOCATION = 'top-toolbar'; 23 24 /** 25 @static 26 @type String 27 @constant 28 */ 29 SC.BOTTOM_LOCATION = 'bottom'; 30 31 /** 32 @class 33 34 Incorporates a segmented view and a container view to display the selected 35 tab. Provide an array of items, which will be passed onto the segmented 36 view. 37 38 @extends SC.View 39 @since SproutCore 1.0 40 */ 41 SC.TabView = SC.View.extend( 42 /** @scope SC.TabView.prototype */ { 43 44 /** @private 45 @type Array 46 @default ['sc-tab-view'] 47 @see SC.View#classNames 48 */ 49 classNames: ['sc-tab-view'], 50 51 /** @private 52 @type Array 53 @default ['nowShowing'] 54 @see SC.View#displayProperties 55 */ 56 displayProperties: ['nowShowing'], 57 58 // .......................................................... 59 // PROPERTIES 60 // 61 62 /** 63 Set nowShowing with the view you want to display. (You may specify globally-accessible views 64 like `MyApp.tabsPage.myTabView`, local views defined on the TabView itself like `myLocalTabView`, 65 or deep local views like `.myLocalPage.myTabView`.) 66 67 @type String 68 @default null 69 */ 70 nowShowing: null, 71 72 /** 73 The list of items for the SegmentedView, and specifying the associated view to display. For example: 74 75 items: [ 76 { title: "Tab 1", value: "MyApp.tabsPage.view1" }, 77 { title: "Tab 2", value: "MyApp.tabsPage.view2" } 78 ] 79 80 (Note that if needed you can specify the item keys by specifying `itemTitleKey`, `itemValueKey`, et 81 cetera, on your TabView.) 82 83 @type Array 84 @default [] 85 */ 86 items: [], 87 88 /** 89 @type String 90 @default null 91 */ 92 itemTitleKey: null, 93 94 /** 95 @type String 96 @default null 97 */ 98 itemValueKey: null, 99 100 /** 101 @type String 102 @default null 103 */ 104 itemIsEnabledKey: null, 105 106 /** 107 @type String 108 @default null 109 */ 110 itemIconKey: null, 111 112 /** 113 @type String 114 @default null 115 */ 116 itemWidthKey: null, 117 118 /** 119 @type String 120 @default null 121 */ 122 itemToolTipKey: null, 123 124 /** 125 @type Number 126 @default SC.REGULAR_BUTTON_HEIGHT 127 */ 128 tabHeight: SC.REGULAR_BUTTON_HEIGHT, 129 130 /** 131 Possible values: 132 133 - SC.TOP_LOCATION 134 - SC.TOP_TOOLBAR_LOCATION 135 - SC.BOTTOM_LOCATION 136 137 @type String 138 @default SC.TOP_LOCATION 139 */ 140 tabLocation: SC.TOP_LOCATION, 141 142 /** 143 If set, then the tab location will be automatically saved in the user 144 defaults. Browsers that support localStorage will automatically store 145 this information locally. 146 147 @type String 148 @default null 149 */ 150 userDefaultKey: null, 151 152 153 // .......................................................... 154 // FORWARDING PROPERTIES 155 // 156 157 /** @private Sync important changes with the child views. */ 158 _tab_nowShowingDidChange: function() { 159 var content = this.get('nowShowing'); 160 161 // Sync the segmented view. 162 this.get('segmentedView').set('value', content); 163 164 // If the user default is set, save it. 165 var defaultKey = this.get('userDefaultKey'); 166 if (defaultKey) { 167 SC.userDefaults.set([defaultKey,'nowShowing'].join(':'), content); 168 } 169 170 // If it's a string, try to turn it into the object it references... 171 if (SC.typeOf(content) === SC.T_STRING && content.length > 0) { 172 var dotspot = content.indexOf('.'); 173 // No dot means a local property, either to this view or this view's page. 174 if (dotspot === -1) { 175 var tempContent = this.get(content); 176 content = SC.kindOf(tempContent, SC.CoreView) ? tempContent : SC.objectForPropertyPath(content, this.get('page')); 177 } 178 // Dot at beginning means local property path. 179 else if (dotspot === 0) { 180 content = this.getPath(content.slice(1)); 181 } 182 // Dot after the beginning 183 else { 184 content = SC.objectForPropertyPath(content); 185 } 186 } 187 188 // Sync the container view. 189 this.get('containerView').set('nowShowing', content); 190 191 return this; 192 }.observes('nowShowing'), 193 194 /** @private */ 195 _tab_itemsDidChange: function() { 196 this.get('segmentedView').set('items', this.get('items')); 197 return this ; 198 }.observes('items'), 199 200 /** @private 201 Restore userDefault key if set. 202 */ 203 init: function() { 204 sc_super(); 205 this._tab_nowShowingDidChange()._tab_itemsDidChange(); 206 // Wake up the userDefaults support, if in use. 207 var defaultKey = this.get('userDefaultKey'); 208 if (defaultKey) { 209 defaultKey = [defaultKey,'nowShowing'].join(':'); 210 var nowShowing = SC.userDefaults.get(defaultKey); 211 if (!SC.none(nowShowing)) this.set('nowShowing', nowShowing); 212 } 213 }, 214 215 /** @private */ 216 createChildViews: function() { 217 var childViews = [], containerView, layout, 218 tabLocation = this.get('tabLocation'), 219 tabHeight = this.get('tabHeight'), 220 controlSize = this.get('controlSize'); 221 222 if (tabLocation === SC.TOP_LOCATION) { 223 layout = { top: tabHeight/2+1, left: 0, right: 0, bottom: 0, border: 1 }; 224 } else if (tabLocation === SC.TOP_TOOLBAR_LOCATION) { 225 layout = { top: tabHeight+1, left: 0, right: 0, bottom: 0, border: 1 }; 226 } else { 227 layout = { top: 0, left: 0, right: 0, bottom: (tabHeight/2) - 1, border: 1 }; 228 } 229 230 containerView = this.containerView.extend({ 231 layout: layout, 232 //adding the role 233 ariaRole: 'tabpanel' 234 }); 235 236 this.containerView = this.createChildView(containerView) ; 237 238 // The segmentedView managed by this tab view. Note that this TabView uses 239 // a custom segmented view. You can access this view but you cannot change 240 // it. 241 layout = (tabLocation === SC.TOP_LOCATION || 242 tabLocation === SC.TOP_TOOLBAR_LOCATION) ? 243 { height: tabHeight, left: 0, right: 0, top: 0 } : 244 { height: tabHeight, left: 0, right: 0, bottom: 0 } ; 245 246 this.segmentedView = this.get('segmentedView').extend({ 247 layout: layout, 248 249 controlSize: controlSize, 250 251 /** @private 252 When the value changes, update the parentView's value as well. 253 */ 254 _sc_tab_segmented_valueDidChange: function() { 255 var pv = this.get('parentView'); 256 if (pv) pv.set('nowShowing', this.get('value')); 257 }.observes('value'), 258 259 /** @private */ 260 init: function() { 261 // before we setup the rest of the view, copy key config properties 262 // from the owner view... 263 var pv = this.get('parentView'); 264 if (pv) { 265 SC._TAB_ITEM_KEYS.forEach(function(k) { this[k] = pv.get(k); }, this); 266 } 267 return sc_super(); 268 } 269 }); 270 271 this.segmentedView = this.createChildView(this.segmentedView); 272 273 childViews.push(this.containerView); 274 childViews.push(this.segmentedView); 275 276 this.set('childViews', childViews); 277 return this; 278 }, 279 280 // .......................................................... 281 // COMPONENT VIEWS 282 // 283 284 /** 285 The containerView managed by this tab view. Note that TabView uses a 286 custom container view. You can access this view but you cannot change 287 it. 288 289 @type SC.View 290 @default SC.ContainerView 291 @readOnly 292 */ 293 containerView: SC.ContainerView.extend({ renderDelegateName: 'wellRenderDelegate' }), 294 295 /** 296 @type SC.View 297 @default SC.SegmentedView 298 */ 299 segmentedView: SC.SegmentedView 300 301 }) ; 302 303 SC._TAB_ITEM_KEYS = ['itemTitleKey', 'itemValueKey', 'itemIsEnabledKey', 'itemIconKey', 'itemWidthKey', 'itemToolTipKey', 'itemActionKey', 'itemTargetKey']; 304