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   @namespace
 11   NavigationBuilder is an implementation of the Builder protocol. It implements
 12   `buildIn`/`Out` (though these only relay to `buildIn`/`OutNavigation, so feel free to
 13   override if needed; the navigation builders will still be accessible).
 14   
 15   Building in and out animates the view in and out to and from the left and right.
 16 */
 17 SC.NavigationBuilder = {
 18 
 19   /**
 20     Walk like a duck.
 21     
 22     @type Boolean
 23     @default YES
 24     @constant
 25   */
 26   isNavigationBuilder: YES,
 27   
 28   /**
 29     The transitions to be used for navigation; these are mixed in to the existing
 30     transitions hash if one exists, or become the transitions hash otherwise.
 31     
 32     If NO, it uses the (hard-coded) defaults.
 33     
 34     @type Boolean
 35     @default NO
 36   */
 37   navigationTransitions: NO,
 38   
 39   initMixin: function() {
 40     // force integrate SC.Animatable
 41     var animatable = SC.Animatable;
 42     if (animatable && !this.isAnimatable) {
 43       // okay, let's mix it in!
 44       this.mixin(animatable);
 45     } else if (!animatable) { 
 46       // check that we actually have SC.Animatable
 47       SC.Logger.error(
 48         "SC.NavigationView and SC.NavigationBuilder require SC.Animatable " + 
 49         "to perform animations, but it is not present. Please ensure your app or framework " +
 50         "references it."
 51       );
 52     }
 53     
 54     var navigationTransitions = this.get("navigationTransitions");
 55     if (!navigationTransitions && SC.Animatable) {
 56       navigationTransitions = {
 57         // these being identical helps us.
 58         left: { duration: 0.25, timing: SC.Animatable.TRANSITION_EASE_IN_OUT, action: "navigationBuildDidFinish" },
 59         transform: { duration: 0.25, timing: SC.Animatable.TRANSITION_EASE_IN_OUT, action: "navigationBuildDidFinish" }
 60       };
 61     }
 62     
 63     // mix in transitions (a base set will have been added by SC.Animatable alrady)
 64     if (SC.Animatable) SC.mixin(this.transitions, navigationTransitions);
 65   },
 66   
 67   /** @private
 68     Determines metrics of the view. This may be adapted to work with non-CSS transforms in future...
 69   */
 70   metrics: function() {
 71     var f = this.computeFrameWithParentFrame();
 72     return f;
 73   },
 74   
 75   /** @private
 76     Applies the supplied CSS transform.
 77   */
 78   transform: function(pos) {
 79     if (SC.platform.supportsCSS3DTransforms) {
 80       this.adjust("transform", "translate3d(" + pos + "px,0px,0px)");
 81     } else {
 82       this.adjust("transform", "translate(" + pos + "px,0px)");
 83     }
 84   },
 85   
 86   buildInNavigation: function() {
 87     // set initial state
 88     var metrics = this.metrics();
 89     this.disableAnimation();
 90     this.transform(this.get("buildDirection") === SC.TO_LEFT ? metrics.width : -metrics.width);
 91     this.enableAnimation();
 92     
 93     // now, (delayed) call transform to go to the correct spot
 94     this.invokeLater("transform", 10, 0);
 95   },
 96   
 97   buildOutNavigation: function() {
 98     // we already have an initial state
 99     var metrics = this.metrics();
100     this.transform(this.get("buildDirection") === SC.TO_LEFT ? -metrics.width : metrics.width);
101   },
102   
103   /**
104     You may override this. If you do, call `buildInNavigation` to call the original functionality.
105     You may need to override `navigationBuildDidFinish` as well if you call `buildInNavigation`.
106   */
107   buildIn: function() {
108     this.buildInNavigation();
109   },
110   
111   /**
112     You may override this. If you do, call `buildOutNavigation` to call the original functionality.
113     You may need to override `navigationBuildDidFinish`as well if you call `buildOutNavigation`.
114   */
115   buildOut: function() {
116     this.buildOutNavigation();
117   },
118   
119   /**
120     This ensures that the view has a CSS transform set, even if it is added without build in, etc.
121   */
122   resetBuild: function() {
123     this.transform(0);
124   },
125   
126   /**
127     Called when the transitions finish.
128   */
129   navigationBuildDidFinish: function() {
130     if (this.isBuildingIn) {
131       this.buildInDidFinish();
132     } else if (this.isBuildingOut) {
133       this.buildOutDidFinish();
134     }
135   }
136   
137 } ;
138 
139