492 lines
15 KiB
JavaScript
492 lines
15 KiB
JavaScript
/*
|
|
Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
|
|
Available via Academic Free License >= 2.1 OR the modified BSD license.
|
|
see: http://dojotoolkit.org/license for details
|
|
*/
|
|
|
|
|
|
if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
dojo._hasResource["dijit._Widget"] = true;
|
|
dojo.provide("dijit._Widget");
|
|
dojo.require("dijit._WidgetBase");
|
|
dojo.require("dijit._base");
|
|
|
|
|
|
|
|
////////////////// DEFERRED CONNECTS ///////////////////
|
|
|
|
// This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets'
|
|
// DOM nodes) until someone actually needs to monitor that event.
|
|
dojo.connect(dojo, "_connect",
|
|
function(/*dijit._Widget*/ widget, /*String*/ event){
|
|
if(widget && dojo.isFunction(widget._onConnect)){
|
|
widget._onConnect(event);
|
|
}
|
|
});
|
|
|
|
dijit._connectOnUseEventHandler = function(/*Event*/ event){};
|
|
|
|
////////////////// ONDIJITCLICK SUPPORT ///////////////////
|
|
|
|
// Keep track of where the last keydown event was, to help avoid generating
|
|
// spurious ondijitclick events when:
|
|
// 1. focus is on a <button> or <a>
|
|
// 2. user presses then releases the ENTER key
|
|
// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
|
|
// 4. onkeyup event fires, causing the ondijitclick handler to fire
|
|
dijit._lastKeyDownNode = null;
|
|
if(dojo.isIE){
|
|
(function(){
|
|
var keydownCallback = function(evt){
|
|
dijit._lastKeyDownNode = evt.srcElement;
|
|
};
|
|
dojo.doc.attachEvent('onkeydown', keydownCallback);
|
|
dojo.addOnWindowUnload(function(){
|
|
dojo.doc.detachEvent('onkeydown', keydownCallback);
|
|
});
|
|
})();
|
|
}else{
|
|
dojo.doc.addEventListener('keydown', function(evt){
|
|
dijit._lastKeyDownNode = evt.target;
|
|
}, true);
|
|
}
|
|
|
|
(function(){
|
|
|
|
dojo.declare("dijit._Widget", dijit._WidgetBase, {
|
|
// summary:
|
|
// Base class for all Dijit widgets.
|
|
//
|
|
// Extends _WidgetBase, adding support for:
|
|
// - deferred connections
|
|
// A call like dojo.connect(myWidget, "onMouseMove", func)
|
|
// will essentially do a dojo.connect(myWidget.domNode, "onMouseMove", func)
|
|
// - ondijitclick
|
|
// Support new dojoAttachEvent="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress
|
|
// - focus related functions
|
|
// In particular, the onFocus()/onBlur() callbacks. Driven internally by
|
|
// dijit/_base/focus.js.
|
|
// - deprecated methods
|
|
// - onShow(), onHide(), onClose()
|
|
//
|
|
// Also, by loading code in dijit/_base, turns on:
|
|
// - browser sniffing (putting browser id like .dj_ie on <html> node)
|
|
// - high contrast mode sniffing (add .dijit_a11y class to <body> if machine is in high contrast mode)
|
|
|
|
|
|
////////////////// DEFERRED CONNECTS ///////////////////
|
|
|
|
// _deferredConnects: [protected] Object
|
|
// attributeMap addendum for event handlers that should be connected only on first use
|
|
_deferredConnects: {
|
|
onClick: "",
|
|
onDblClick: "",
|
|
onKeyDown: "",
|
|
onKeyPress: "",
|
|
onKeyUp: "",
|
|
onMouseMove: "",
|
|
onMouseDown: "",
|
|
onMouseOut: "",
|
|
onMouseOver: "",
|
|
onMouseLeave: "",
|
|
onMouseEnter: "",
|
|
onMouseUp: ""
|
|
},
|
|
|
|
onClick: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onClick: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of mouse click events.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onDblClick: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onDblClick: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of mouse double click events.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onKeyDown: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onKeyDown: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of keys being pressed down.
|
|
// event:
|
|
// key Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onKeyPress: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onKeyPress: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of printable keys being typed.
|
|
// event:
|
|
// key Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onKeyUp: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onKeyUp: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of keys being released.
|
|
// event:
|
|
// key Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onMouseDown: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onMouseDown: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of when the mouse button is pressed down.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onMouseMove: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onMouseMove: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onMouseOut: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onMouseOut: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onMouseOver: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onMouseOver: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onMouseLeave: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onMouseLeave: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of when the mouse moves off of this widget.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onMouseEnter: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onMouseEnter: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of when the mouse moves onto this widget.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
onMouseUp: dijit._connectOnUseEventHandler,
|
|
/*=====
|
|
onMouseUp: function(event){
|
|
// summary:
|
|
// Connect to this function to receive notifications of when the mouse button is released.
|
|
// event:
|
|
// mouse Event
|
|
// tags:
|
|
// callback
|
|
},
|
|
=====*/
|
|
|
|
create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
|
|
// To avoid double-connects, remove entries from _deferredConnects
|
|
// that have been setup manually by a subclass (ex, by dojoAttachEvent).
|
|
// If a subclass has redefined a callback (ex: onClick) then assume it's being
|
|
// connected to manually.
|
|
this._deferredConnects = dojo.clone(this._deferredConnects);
|
|
for(var attr in this.attributeMap){
|
|
delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
|
|
}
|
|
for(attr in this._deferredConnects){
|
|
if(this[attr] !== dijit._connectOnUseEventHandler){
|
|
delete this._deferredConnects[attr]; // redefined, probably dojoAttachEvent exists
|
|
}
|
|
}
|
|
|
|
this.inherited(arguments);
|
|
|
|
if(this.domNode){
|
|
// If the developer has specified a handler as a widget parameter
|
|
// (ex: new Button({onClick: ...})
|
|
// then naturally need to connect from DOM node to that handler immediately,
|
|
for(attr in this.params){
|
|
this._onConnect(attr);
|
|
}
|
|
}
|
|
},
|
|
|
|
_onConnect: function(/*String*/ event){
|
|
// summary:
|
|
// Called when someone connects to one of my handlers.
|
|
// "Turn on" that handler if it isn't active yet.
|
|
//
|
|
// This is also called for every single initialization parameter
|
|
// so need to do nothing for parameters like "id".
|
|
// tags:
|
|
// private
|
|
if(event in this._deferredConnects){
|
|
var mapNode = this[this._deferredConnects[event] || 'domNode'];
|
|
this.connect(mapNode, event.toLowerCase(), event);
|
|
delete this._deferredConnects[event];
|
|
}
|
|
},
|
|
|
|
////////////////// FOCUS RELATED ///////////////////
|
|
// _onFocus() and _onBlur() are called by the focus manager
|
|
|
|
// focused: [readonly] Boolean
|
|
// This widget or a widget it contains has focus, or is "active" because
|
|
// it was recently clicked.
|
|
focused: false,
|
|
|
|
isFocusable: function(){
|
|
// summary:
|
|
// Return true if this widget can currently be focused
|
|
// and false if not
|
|
return this.focus && (dojo.style(this.domNode, "display") != "none");
|
|
},
|
|
|
|
onFocus: function(){
|
|
// summary:
|
|
// Called when the widget becomes "active" because
|
|
// it or a widget inside of it either has focus, or has recently
|
|
// been clicked.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
onBlur: function(){
|
|
// summary:
|
|
// Called when the widget stops being "active" because
|
|
// focus moved to something outside of it, or the user
|
|
// clicked somewhere outside of it, or the widget was
|
|
// hidden.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
_onFocus: function(e){
|
|
// summary:
|
|
// This is where widgets do processing for when they are active,
|
|
// such as changing CSS classes. See onFocus() for more details.
|
|
// tags:
|
|
// protected
|
|
this.onFocus();
|
|
},
|
|
|
|
_onBlur: function(){
|
|
// summary:
|
|
// This is where widgets do processing for when they stop being active,
|
|
// such as changing CSS classes. See onBlur() for more details.
|
|
// tags:
|
|
// protected
|
|
this.onBlur();
|
|
},
|
|
|
|
////////////////// DEPRECATED METHODS ///////////////////
|
|
|
|
setAttribute: function(/*String*/ attr, /*anything*/ value){
|
|
// summary:
|
|
// Deprecated. Use set() instead.
|
|
// tags:
|
|
// deprecated
|
|
dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
|
|
this.set(attr, value);
|
|
},
|
|
|
|
attr: function(/*String|Object*/name, /*Object?*/value){
|
|
// summary:
|
|
// Set or get properties on a widget instance.
|
|
// name:
|
|
// The property to get or set. If an object is passed here and not
|
|
// a string, its keys are used as names of attributes to be set
|
|
// and the value of the object as values to set in the widget.
|
|
// value:
|
|
// Optional. If provided, attr() operates as a setter. If omitted,
|
|
// the current value of the named property is returned.
|
|
// description:
|
|
// This method is deprecated, use get() or set() directly.
|
|
|
|
// Print deprecation warning but only once per calling function
|
|
if(dojo.config.isDebug){
|
|
var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
|
|
caller = (arguments.callee.caller || "unknown caller").toString();
|
|
if(!alreadyCalledHash[caller]){
|
|
dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
|
|
caller, "", "2.0");
|
|
alreadyCalledHash[caller] = true;
|
|
}
|
|
}
|
|
|
|
var args = arguments.length;
|
|
if(args >= 2 || typeof name === "object"){ // setter
|
|
return this.set.apply(this, arguments);
|
|
}else{ // getter
|
|
return this.get(name);
|
|
}
|
|
},
|
|
|
|
////////////////// ONDIJITCLICK SUPPORT ///////////////////
|
|
|
|
// nodesWithKeyClick: [private] String[]
|
|
// List of nodes that correctly handle click events via native browser support,
|
|
// and don't need dijit's help
|
|
nodesWithKeyClick: ["input", "button"],
|
|
|
|
connect: function(
|
|
/*Object|null*/ obj,
|
|
/*String|Function*/ event,
|
|
/*String|Function*/ method){
|
|
// summary:
|
|
// Connects specified obj/event to specified method of this object
|
|
// and registers for disconnect() on widget destroy.
|
|
// description:
|
|
// Provide widget-specific analog to dojo.connect, except with the
|
|
// implicit use of this widget as the target object.
|
|
// This version of connect also provides a special "ondijitclick"
|
|
// event which triggers on a click or space or enter keyup.
|
|
// Events connected with `this.connect` are disconnected upon
|
|
// destruction.
|
|
// returns:
|
|
// A handle that can be passed to `disconnect` in order to disconnect before
|
|
// the widget is destroyed.
|
|
// example:
|
|
// | var btn = new dijit.form.Button();
|
|
// | // when foo.bar() is called, call the listener we're going to
|
|
// | // provide in the scope of btn
|
|
// | btn.connect(foo, "bar", function(){
|
|
// | console.debug(this.toString());
|
|
// | });
|
|
// tags:
|
|
// protected
|
|
|
|
var d = dojo,
|
|
dc = d._connect,
|
|
handles = this.inherited(arguments, [obj, event == "ondijitclick" ? "onclick" : event, method]);
|
|
|
|
if(event == "ondijitclick"){
|
|
// add key based click activation for unsupported nodes.
|
|
// do all processing onkey up to prevent spurious clicks
|
|
// for details see comments at top of this file where _lastKeyDownNode is defined
|
|
if(d.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button
|
|
var m = d.hitch(this, method);
|
|
handles.push(
|
|
dc(obj, "onkeydown", this, function(e){
|
|
//console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
|
|
if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
|
|
!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
|
|
// needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
|
|
dijit._lastKeyDownNode = e.target;
|
|
|
|
// Stop event to prevent scrolling on space key in IE.
|
|
// But don't do this for _HasDropDown because it surpresses the onkeypress
|
|
// event needed to open the drop down when the user presses the SPACE key.
|
|
if(!("openDropDown" in this && obj == this._buttonNode)){
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
}),
|
|
dc(obj, "onkeyup", this, function(e){
|
|
//console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
|
|
if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
|
|
e.target == dijit._lastKeyDownNode && // === breaks greasemonkey
|
|
!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
|
|
//need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
|
|
dijit._lastKeyDownNode = null;
|
|
return m(e);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
return handles; // _Widget.Handle
|
|
},
|
|
|
|
////////////////// MISCELLANEOUS METHODS ///////////////////
|
|
|
|
_onShow: function(){
|
|
// summary:
|
|
// Internal method called when this widget is made visible.
|
|
// See `onShow` for details.
|
|
this.onShow();
|
|
},
|
|
|
|
onShow: function(){
|
|
// summary:
|
|
// Called when this widget becomes the selected pane in a
|
|
// `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
|
|
// `dijit.layout.AccordionContainer`, etc.
|
|
//
|
|
// Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
onHide: function(){
|
|
// summary:
|
|
// Called when another widget becomes the selected pane in a
|
|
// `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
|
|
// `dijit.layout.AccordionContainer`, etc.
|
|
//
|
|
// Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
onClose: function(){
|
|
// summary:
|
|
// Called when this widget is being displayed as a popup (ex: a Calendar popped
|
|
// up from a DateTextBox), and it is hidden.
|
|
// This is called from the dijit.popup code, and should not be called directly.
|
|
//
|
|
// Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
|
|
// Callback if a user tries to close the child. Child will be closed if this function returns true.
|
|
// tags:
|
|
// extension
|
|
|
|
return true; // Boolean
|
|
}
|
|
});
|
|
|
|
})();
|
|
|
|
}
|