// ========================================================================== // Project: SproutCore
- JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // Portions ©2008-2011 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ==========================================================================
sc_require(“views/workspace”);
/**
@static @type String @constant
*/ SC
.TO_LEFT = “TOLEFT”;
/**
@static @type String @constant
*/ SC
.TO_RIGHT = “TORIGHT”;
/** @class
NavigationView is very loosely based on UINavigationController: that is, it implements a push/pop based API. NavigationView checks if the view is NavigationBuildable--that is, if it has Views may specify a topToolbar or bottomToolbar property. These will become the top or bottom toolbars of the NavigationView (which is, incidentally, a WorkspaceView). Of course, this process is animated... @author Alex Iskander @extends SC.WorkspaceView @since SproutCore 1.4
*/ SC
.NavigationView = SC
.WorkspaceView.extend( /** @scope SC
.NavigationView.prototype */ {
/** @private */ _views: null, /** @private */ _current: null, /** @type SC.View @default SC.View */ navigationContentView: SC.View, /** @private */ init: function() { sc_super(); this._views = []; }, /** @private */ createChildViews: function() { sc_super(); // get the content var content = this.get("navigationContentView"); // instantiate if needed if (content.isClass) content = this.createChildView(content); // set internal values this._defaultContent = this.navigationContentView = content; // append to the content view this.contentView.appendChild(content); }, /** @private */ changeNavigationContent: function(view) { var top = null, bottom = null; // find top and bottom toolbars if we are setting it to a view if (view) { top = view.get("topToolbar"); bottom = view.get("bottomToolbar"); } // instantiate top if needed if (top && top.isClass) { view.set("topToolbar", top = top.create()); } // and now bottom if (bottom && bottom.isClass) { view.set("bottomToolbar", bottom = bottom.create()); } // batch property changes for efficiency this.beginPropertyChanges(); // update current, etc. etc. this._current = view; this.set("navigationContentView", view ? view : this._defaultContent); // set the top/bottom appropriately this.set("topToolbar", top); this.set("bottomToolbar", bottom); // and we are done this.endPropertyChanges(); }, /** Pushes a view into the navigation view stack. The view may have topToolbar and bottomToolbar properties. @param {SC.View} view The view to display */ push: function(view) { this._currentDirection = this._current ? SC.TO_LEFT : null; // add current view to the stack (if needed) if (this._current) this._views.push(this._current); // update content now... this.changeNavigationContent(view); }, /** Pops the current view off the navigation view stack. */ pop: function() { this._currentDirection = SC.TO_RIGHT; // pop the view var view = this._views.pop(); // set new (old) content view this.changeNavigationContent(view); }, /** Pops to the specified view on the navigation view stack; the view you pass will become the current view. @param {SC.View} toView The view to display */ popToView: function(toView) { this._currentDirection = SC.TO_RIGHT; var views = this._views, idx = views.length - 1, view = views[idx]; // loop back from end while (view && view !== toView) { this._views.pop(); idx--; view = views[idx]; } // and change the content this.changeNavigationContent(view); }, /** @private */ topToolbarDidChange: function() { var active = this.activeTopToolbar, replacement = this.get("topToolbar"); // if we have an active toolbar, set the build direction and build out if (active) { if (this._currentDirection !== null) { active.set("buildDirection", this._currentDirection); this.buildOutChild(active); } else { this.removeChild(active); } } // if we have a new toolbar, set the build direction and build in if (replacement) { if (this._currentDirection !== null) { replacement.set("buildDirection", this._currentDirection); this.buildInChild(replacement); } else { this.appendChild(replacement); } } // update, and queue retiling this.activeTopToolbar = replacement; this.invokeOnce("childDidChange"); }.observes("topToolbar"), /** @private */ bottomToolbarDidChange: function() { var active = this.activeBottomToolbar, replacement = this.get("bottomToolbar"); if (active) { if (this._currentDirection !== null) { active.set("buildDirection", this._currentDirection); this.buildOutChild(active); } else { this.removeChild(active); } } if (replacement) { if (this._currentDirection !== null) { replacement.set("buildDirection", this._currentDirection); this.buildInChild(replacement); } else { this.appendChild(replacement); } } this.activeBottomToolbar = replacement; this.invokeOnce("childDidChange"); }.observes("topToolbar"), /** @private */ contentViewDidChange: function() { var active = this.activeNavigationContentView, replacement = this.get("navigationContentView"); // mix in navigationbuilder if needed if (!replacement.isNavigationBuilder) { replacement.mixin(SC.NavigationBuilder); } // tiling really needs to happen _before_ animation // so, we set "pending" and queue tiling. this._pendingBuildOut = active; this._pendingBuildIn = replacement; this.activeNavigationContentView = replacement; this.invokeOnce("childDidChange"); }.observes("navigationContentView"), /** @private */ childDidChange: function() { var replacement = this._pendingBuildIn, active = this._pendingBuildOut; if (active) { if (this._currentDirection !== null) { active.set("buildDirection", this._currentDirection); this.contentView.buildOutChild(active); } else { this.contentView.removeChild(active); } } this._scws_tile(); if (replacement) { if (this._currentDirection !== null) { replacement.set("buildDirection", this._currentDirection); this.contentView.buildInChild(replacement); } else { this.contentView.appendChild(replacement); } } }
});