// ========================================================================
// SproutCore
// copyright 2006-2008 Sprout Systems, Inc.
// ========================================================================
require('views/view') ;
/**
@class
This is a basic popup menu. You can show the popup menu by calling the
view's popup() method. Pass in the root element and event so that is can
be positioned.
@extends SC.View
*/
SC.PopupMenuView = SC.View.extend({
emptyElement: "
",
acceptsFirstResponder: true,
keyDown: function(evt)
{
return this.interpretKeyEvents(evt);
},
// interpretKeyEvents callbacks...
cancel: function()
{
this.set('currentSelectedMenuItem', null);
this.set('isVisible', false);
},
moveUp: function()
{
this.selectPreviousMenuItem();
},
moveDown: function()
{
this.selectNextMenuItem();
},
_currentSelectedMenuItem: null,
currentSelectedMenuItem: function( key, value )
{
if (value !== undefined)
{
if (this._currentSelectedMenuItem) this._currentSelectedMenuItem.set('isDefault', false);
this._currentSelectedMenuItem = value;
if (this._currentSelectedMenuItem) this._currentSelectedMenuItem.set('isDefault', true);
}
return this._currentSelectedMenuItem;
}.property(),
selectPreviousMenuItem: function()
{
var item = this.previousValidMenuItem();
if (!item) return false;
this.set('currentSelectedMenuItem', item);
},
selectNextMenuItem: function()
{
var item = this.nextValidMenuItem();
if (!item) return false;
this.set('currentSelectedMenuItem', item);
},
previousValidMenuItem: function()
{
return this._validMenuItemInDirection('previousSibling', 'lastChild');
},
nextValidMenuItem: function()
{
return this._validMenuItemInDirection('nextSibling', 'firstChild');
},
_validMenuItemInDirection: function( direction, begin )
{
var curr = this.get('currentSelectedMenuItem');
var view = curr ? curr.get(direction) : this.get(begin);
if (!view) return null;
do {
if (view.get('isEnabled')) return view;
} while (view = view.get(direction));
return null;
},
_show: function()
{
// clear out any previously used selection value...
this.set('currentSelectedMenuItem', null);
var menuItems = this.get('childNodes');
for (var i=0, n=menuItems.length; i < n; i++)
{
// for each menu item, get the action that it performs and the current target for that action
var sender = menuItems[i];
// old function style actions... skip validating and let them be
if (sender._hasLegacyActionHandler()) continue;
var action = sender.get('action');
var target = SC.app.targetForAction(action, sender.get('target'), sender);
//console.log( "action: %s, target: %o", action, target );
// found a target and the target validates, menu item is enabled if the validator returns true
if (target && target.respondsTo('validateMenuItem')) sender.set('isEnabled', target.validateMenuItem(sender));
// found a target and it chooses not to validate, menu item is enabled
if (target && !target.respondsTo('validateMenuItem')) sender.set('isEnabled', true);
// unable to resolve a target for this action, therefor disable the menu item
if (!target) sender.set('isEnabled', false);
}
// call the superclasses _show method to make the menu visible
arguments.callee.base.apply(this, arguments);
},
resizeWithOldParentSize: function() {
// loop through child views (which should be menu items), and get their
// required widths. Use the maximum returned width.
var requiredWidth = 0;
var child = this.get('firstChild') ;
while(child) {
var w = (child.computedRequiredWidth) ? child.computedRequiredWidth():0;
if (w > requiredWidth) requiredWidth = w ;
child = child.get('nextSibling') ;
}
var oldWidth = this.get("size").width;
if(requiredWidth != oldWidth)
{
var size = { width: requiredWidth };
// set this view to the same size.
this.set('size',size) ;
}
}
});