1 sc_require("views/view"); 2 3 SC.View.reopen( 4 /** @scope SC.View.prototype */{ 5 6 /** 7 Handles changes in the layer id. 8 */ 9 layerIdDidChange: function() { 10 var layer = this.get('layer'), 11 lid = this.get('layerId'), 12 lastId = this._lastLayerId; 13 14 if (lid !== lastId) { 15 // if we had an earlier one, remove from view hash. 16 if (lastId && SC.View.views[lastId] === this) { 17 delete SC.View.views[lastId]; 18 } 19 20 // set the current one as the new old one 21 this._lastLayerId = lid; 22 23 // and add the new one 24 SC.View.views[lid] = this; 25 26 // and finally, set the actual layer id. 27 if (layer) { layer.id = lid; } 28 } 29 }.observes("layerId"), 30 31 // ------------------------------------------------------------------------ 32 // LAYER LOCATION 33 // 34 35 /** 36 Insert the view into the the receiver's childNodes array. 37 38 The view will be added to the childNodes array before the beforeView. If 39 beforeView is null, then the view will be added to the end of the array. 40 This will also add the view's rootElement DOM node to the receivers 41 containerElement DOM node as a child. 42 43 If the specified view already belongs to another parent, it will be 44 removed from that view first. 45 46 @param {SC.View} view 47 @param {SC.View} beforeView 48 @returns {SC.View} the receiver 49 */ 50 insertBefore: function(view, beforeView) { 51 view.beginPropertyChanges(); // limit notifications 52 53 // Reset any views that are already building in or out. 54 if (view.resetBuildState) { view.resetBuildState(); } 55 view._doAdopt(this, beforeView); 56 57 view.endPropertyChanges(); 58 59 return this ; 60 }, 61 62 /** 63 Replace the oldView with the specified view in the receivers childNodes 64 array. This will also replace the DOM node of the oldView with the DOM 65 node of the new view in the receivers DOM. 66 67 If the specified view already belongs to another parent, it will be 68 removed from that view first. 69 70 @param view {SC.View} the view to insert in the DOM 71 @param view {SC.View} the view to remove from the DOM. 72 @returns {SC.View} the receiver 73 */ 74 replaceChild: function(view, oldView) { 75 // suspend notifications 76 view.beginPropertyChanges(); 77 oldView.beginPropertyChanges(); 78 this.beginPropertyChanges(); 79 80 this.insertBefore(view,oldView).removeChild(oldView) ; 81 82 // resume notifications 83 this.endPropertyChanges(); 84 oldView.endPropertyChanges(); 85 view.endPropertyChanges(); 86 87 return this; 88 }, 89 90 /** 91 Replaces the current array of child views with the new array of child 92 views. 93 94 This will remove *and* destroy all of the existing child views and their 95 layers. 96 97 Warning: The new array must be made of *child* views (i.e. created using 98 this.createChildView() on the parent). 99 100 @param {Array} newChildViews Child views you want to add 101 @returns {SC.View} receiver 102 */ 103 replaceAllChildren: function (newChildViews) { 104 this.beginPropertyChanges(); 105 106 // If rendered, destroy our layer so we can re-render. 107 // if (this.get('_isRendered')) { 108 // var layer = this.get('layer'); 109 110 // // If attached, detach and track our parent node so we can re-attach. 111 // if (this.get('isAttached')) { 112 // // We don't allow for transitioning out at this time. 113 // // TODO: support transition out of child views. 114 // this._doDetach(true); 115 // } 116 117 // // Destroy our layer in one move. 118 // this.destroyLayer(); 119 // } 120 121 // Remove the current child views. 122 // We aren't rendered at this point so it bypasses the optimization in 123 // removeAllChildren that would recreate the layer. We would rather add the 124 // new childViews before recreating the layer. 125 this.removeAllChildren(true); 126 127 // Add the new children. 128 for (var i = 0, len = newChildViews.get('length'); i < len; i++) { 129 this.appendChild(newChildViews.objectAt(i)); 130 } 131 132 // We were rendered previously. 133 // if (layer) { 134 // // Recreate our layer (now empty). 135 // this.createLayer(); 136 // } 137 this.endPropertyChanges(); 138 139 return this ; 140 }, 141 142 /** 143 Appends the specified view to the end of the receivers childViews array. 144 This is equivalent to calling insertBefore(view, null); 145 146 @param view {SC.View} the view to insert 147 @returns {SC.View} the receiver 148 */ 149 appendChild: function(view) { 150 return this.insertBefore(view, null); 151 }, 152 153 // ------------------------------------------------------------------------ 154 // BUILDING IN/OUT 155 // 156 157 /** 158 Call this to append a child while building it in. If the child is not 159 buildable, this is the same as calling appendChild. 160 161 @deprecated Version 1.10 162 */ 163 buildInChild: function(view) { 164 view.willBuildInToView(this); 165 this.appendChild(view); 166 view.buildInToView(this); 167 }, 168 169 /** 170 Call to remove a child after building it out. If the child is not buildable, 171 this will simply call removeChild. 172 173 @deprecated Version 1.10 174 */ 175 buildOutChild: function(view) { 176 view.buildOutFromView(this); 177 }, 178 179 /** 180 Called by child view when build in finishes. By default, does nothing. 181 182 @deprecated Version 1.10 183 */ 184 buildInDidFinishFor: function(child) { 185 }, 186 187 /** 188 @private 189 Called by child view when build out finishes. By default removes the child view. 190 */ 191 buildOutDidFinishFor: function(child) { 192 this.removeChild(child); 193 }, 194 195 /** 196 Whether the view is currently building in. 197 198 @deprecated Version 1.10 199 */ 200 isBuildingIn: NO, 201 202 /** 203 Whether the view is currently building out. 204 205 @deprecated Version 1.10 206 */ 207 isBuildingOut: NO, 208 209 /** 210 Implement this, and call didFinishBuildIn when you are done. 211 212 @deprecated Version 1.10 213 */ 214 buildIn: function() { 215 //@if(debug) 216 SC.warn("The SC.View build methods have been deprecated in favor of the transition plugins. To build in a view, please provide a transitionIn plugin (many are pre-built in SproutCore) and to build out a view, please provide a transitionOut plugin."); 217 //@endif 218 this.buildInDidFinish(); 219 }, 220 221 /** 222 Implement this, and call didFinishBuildOut when you are done. 223 224 @deprecated Version 1.10 225 */ 226 buildOut: function() { 227 //@if(debug) 228 SC.warn("The SC.View build methods have been deprecated in favor of the transition plugins. To build in a view, please provide a transitionIn plugin (many are pre-built in SproutCore) and to build out a view, please provide a transitionOut plugin."); 229 //@endif 230 this.buildOutDidFinish(); 231 }, 232 233 /** 234 This should reset (without animation) any internal states; sometimes called before. 235 236 It is usually called before a build in, by the parent view. 237 @deprecated Version 1.10 238 */ 239 resetBuild: function() { 240 241 }, 242 243 /** 244 Implement this if you need to do anything special when cancelling build out; 245 note that buildIn will subsequently be called, so you usually won't need to do 246 anything. 247 248 This is basically called whenever build in happens. 249 250 @deprecated Version 1.10 251 */ 252 buildOutDidCancel: function() { 253 254 }, 255 256 /** 257 Implement this if you need to do anything special when cancelling build in. 258 You probably won't be able to do anything. I mean, what are you gonna do? 259 260 If build in was cancelled, it means build out is probably happening. 261 So, any timers or anything you had going, you can cancel. 262 Then buildOut will happen. 263 264 @deprecated Version 1.10 265 */ 266 buildInDidCancel: function() { 267 268 }, 269 270 /** 271 Call this when you have built in. 272 273 @deprecated Version 1.10 274 */ 275 buildInDidFinish: function() { 276 this.isBuildingIn = NO; 277 this._buildingInTo.buildInDidFinishFor(this); 278 this._buildingInTo = null; 279 }, 280 281 /** 282 Call this when you have finished building out. 283 284 @deprecated Version 1.10 285 */ 286 buildOutDidFinish: function() { 287 this.isBuildingOut = NO; 288 this._buildingOutFrom.buildOutDidFinishFor(this); 289 this._buildingOutFrom = null; 290 }, 291 292 /** 293 Usually called by parentViewDidChange, this resets the build state (calling resetBuild in the process). 294 295 @deprecated Version 1.10 296 */ 297 resetBuildState: function() { 298 if (this.isBuildingIn) { 299 this.buildInDidCancel(); 300 this.isBuildingIn = NO; 301 } 302 if (this.isBuildingOut) { 303 this.buildOutDidCancel(); 304 this.isBuildingOut = NO; 305 } 306 307 // finish cleaning up 308 this.buildingInTo = null; 309 this.buildingOutFrom = null; 310 311 this.resetBuild(); 312 }, 313 314 /** 315 @private (semi) 316 Called by building parent view's buildInChild method. This prepares 317 to build in, but unlike buildInToView, this is called _before_ the child 318 is appended. 319 320 Mostly, this cancels any build out _before_ the view is removed through parent change. 321 */ 322 willBuildInToView: function(view) { 323 // stop any current build outs (and if we need to, we also need to build in again) 324 if (this.isBuildingOut) { 325 this.buildOutDidCancel(); 326 } 327 }, 328 329 /** 330 @private (semi) 331 Called by building parent view's buildInChild method. 332 */ 333 buildInToView: function(view) { 334 // if we are already building in, do nothing. 335 if (this.isBuildingIn) { return; } 336 337 this._buildingInTo = view; 338 this.isBuildingOut = NO; 339 this.isBuildingIn = YES; 340 this.buildIn(); 341 }, 342 343 /** 344 @private (semi) 345 Called by building parent view's buildOutChild method. 346 347 The supplied view should always be the parent view. 348 */ 349 buildOutFromView: function(view) { 350 // if we are already building out, do nothing. 351 if (this.isBuildingOut) { return; } 352 353 // cancel any build ins 354 if (this.isBuildingIn) { 355 this.buildInDidCancel(); 356 } 357 358 // in any case, we need to build out 359 this.isBuildingOut = YES; 360 this.isBuildingIn = NO; 361 this._buildingOutFrom = view; 362 this.buildOut(); 363 } 364 }); 365