- Author:
- David Nickerson <nickerso@users.sourceforge.net>
- Date:
- 2009-07-16 02:00:03+12:00
- Desc:
- the starting point for the HH tutorial example
- Permanent Source URI:
- https://models.fieldml.org/workspace/a1/rawfile/f6a8f90307388eb4b040ee3566b84d88b59247f7/dojo-presentation/js/dojo/dijit/form/_FormWidget.js
dojo.provide("dijit.form._FormWidget");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated],
{
/*
Summary:
_FormWidget's correspond to native HTML elements such as <checkbox> or <button>.
Each _FormWidget represents a single HTML element.
All these widgets should have these attributes just like native HTML input elements.
You can set them during widget construction.
They also share some common methods.
*/
// baseClass: String
// Root CSS class of the widget (ex: dijitTextBox), used to add CSS classes of widget
// (ex: "dijitTextBox dijitTextBoxInvalid dijitTextBoxFocused dijitTextBoxInvalidFocused")
// See _setStateClass().
baseClass: "",
// name: String
// Name used when submitting form; same as "name" attribute or plain HTML elements
name: "",
// alt: String
// Corresponds to the native HTML <input> element's attribute.
alt: "",
// value: String
// Corresponds to the native HTML <input> element's attribute.
value: "",
// type: String
// Corresponds to the native HTML <input> element's attribute.
type: "text",
// tabIndex: Integer
// Order fields are traversed when user hits the tab key
tabIndex: "0",
// disabled: Boolean
// Should this widget respond to user input?
// In markup, this is specified as "disabled='disabled'", or just "disabled".
disabled: false,
// readOnly: Boolean
// Should this widget respond to user input?
// In markup, this is specified as "readOnly".
// Similar to disabled except readOnly form values are submitted
readOnly: false,
// intermediateChanges: Boolean
// Fires onChange for each value change or only on demand
intermediateChanges: false,
// These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
// Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
// directly in the template as read by the parser in order to function. IE is known to specifically
// require the 'name' attribute at element creation time.
attributeMap: dojo.mixin(dojo.clone(dijit._Widget.prototype.attributeMap),
{value:"focusNode", disabled:"focusNode", readOnly:"focusNode", id:"focusNode", tabIndex:"focusNode", alt:"focusNode"}),
setAttribute: function(/*String*/ attr, /*anything*/ value){
this.inherited(arguments);
switch(attr){
case "disabled":
var tabIndexNode = this[this.attributeMap['tabIndex']||'domNode'];
if(value){
//reset those, because after the domNode is disabled, we can no longer receive
//mouse related events, see #4200
this._hovering = false;
this._active = false;
// remove the tabIndex, especially for FF
tabIndexNode.removeAttribute('tabIndex');
}else{
tabIndexNode.setAttribute('tabIndex', this.tabIndex);
}
dijit.setWaiState(this[this.attributeMap['disabled']||'domNode'], "disabled", value);
this._setStateClass();
}
},
setDisabled: function(/*Boolean*/ disabled){
// summary:
// Set disabled state of widget (Deprecated).
dojo.deprecated("setDisabled("+disabled+") is deprecated. Use attr('disabled',"+disabled+") instead.", "", "2.0");
this.setAttribute('disabled', disabled);
},
_onFocus: function(e){
dijit.scrollIntoView(this.domNode);
this.inherited(arguments);
},
_onMouse : function(/*Event*/ event){
// summary:
// Sets _hovering, _active, and stateModifier properties depending on mouse state,
// then calls setStateClass() to set appropriate CSS classes for this.domNode.
//
// To get a different CSS class for hover, send onmouseover and onmouseout events to this method.
// To get a different CSS class while mouse button is depressed, send onmousedown to this method.
var mouseNode = event.currentTarget;
if(mouseNode && mouseNode.getAttribute){
this.stateModifier = mouseNode.getAttribute("stateModifier") || "";
}
if(!this.disabled){
switch(event.type){
case "mouseenter":
case "mouseover":
this._hovering = true;
this._active = this._mouseDown;
break;
case "mouseout":
case "mouseleave":
this._hovering = false;
this._active = false;
break;
case "mousedown" :
this._active = true;
this._mouseDown = true;
// set a global event to handle mouseup, so it fires properly
// even if the cursor leaves the button
var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
//if user clicks on the button, even if the mouse is released outside of it,
//this button should get focus (which mimics native browser buttons)
if(this._mouseDown && this.isFocusable()){
this.focus();
}
this._active = false;
this._mouseDown = false;
this._setStateClass();
this.disconnect(mouseUpConnector);
});
break;
}
this._setStateClass();
}
},
isFocusable: function(){
return !this.disabled && !this.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none");
},
focus: function(){
dijit.focus(this.focusNode);
},
_setStateClass: function(){
// summary
// Update the visual state of the widget by setting the css classes on this.domNode
// (or this.stateNode if defined) by combining this.baseClass with
// various suffixes that represent the current widget state(s).
//
// In the case where a widget has multiple
// states, it sets the class based on all possible
// combinations. For example, an invalid form widget that is being hovered
// will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
//
// For complex widgets with multiple regions, there can be various hover/active states,
// such as "Hover" or "CloseButtonHover" (for tab buttons).
// This is controlled by a stateModifier="CloseButton" attribute on the close button node.
//
// The widget may have one or more of the following states, determined
// by this.state, this.checked, this.valid, and this.selected:
// Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
// Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
// Selected - ex: currently selected tab will have this.selected==true
//
// In addition, it may have one or more of the following states,
// based on this.disabled and flags set in _onMouse (this._active, this._hovering, this._focused):
// Disabled - if the widget is disabled
// Active - if the mouse (or space/enter key?) is being pressed down
// Focused - if the widget has focus
// Hover - if the mouse is over the widget
// Get original (non state related, non baseClass related) class specified in template
if(!("staticClass" in this)){
this.staticClass = (this.stateNode||this.domNode).className;
}
// Compute new set of classes
var classes = this.baseClass.split(" ");
function multiply(modifier){
classes=classes.concat(dojo.map(classes, function(c){ return c+modifier; }), "dijit"+modifier);
}
if(this.checked){
multiply("Checked");
}
if(this.state){
multiply(this.state);
}
if(this.selected){
multiply("Selected");
}
if(this.disabled){
multiply("Disabled");
}else if(this.readOnly){
multiply("ReadOnly");
}else if(this._active){
multiply(this.stateModifier+"Active");
}else{
if(this._focused){
multiply("Focused");
}
if(this._hovering){
multiply(this.stateModifier+"Hover");
}
}
(this.stateNode || this.domNode).className = this.staticClass + " " + classes.join(" ");
},
compare: function(/*anything*/val1, /*anything*/val2){
// summary: compare 2 values
if((typeof val1 == "number") && (typeof val2 == "number")){
return (isNaN(val1) && isNaN(val2))? 0 : (val1-val2);
}else if(val1 > val2){ return 1; }
else if(val1 < val2){ return -1; }
else { return 0; }
},
onChange: function(newValue){
// summary: callback when value is changed
},
_onChangeMonitor: 'value',
_onChangeActive: false,
_handleOnChange: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
// summary: set the value of the widget.
this._lastValue = newValue;
if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
this._resetValue = this._lastValueReported = newValue;
}
if((this.intermediateChanges || priorityChange || priorityChange === undefined) &&
((typeof newValue != typeof this._lastValueReported) ||
this.compare(newValue, this._lastValueReported) != 0)){
this._lastValueReported = newValue;
if(this._onChangeActive){ this.onChange(newValue); }
}
},
reset: function(){
this._hasBeenBlurred = false;
if(this.setValue && !this._getValueDeprecated){
this.setValue(this._resetValue, true);
}else if(this._onChangeMonitor){
this.setAttribute(this._onChangeMonitor, (this._resetValue !== undefined && this._resetValue !== null)? this._resetValue : '');
}
},
create: function(){
this.inherited(arguments);
this._onChangeActive = true;
this._setStateClass();
},
destroy: function(){
if(this._layoutHackHandle){
clearTimeout(this._layoutHackHandle);
}
this.inherited(arguments);
},
setValue: function(/*String*/ value){
dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use attr('value',"+value+") instead.", "", "2.0");
this.setAttribute('value', value);
},
_getValueDeprecated: true, // Form uses this, remove when getValue is removed
getValue: function(){
dojo.deprecated("dijit.form._FormWidget:getValue() is deprecated. Use widget.value instead.", "", "2.0");
return this.value;
},
_layoutHack: function(){
// summary: work around table sizing bugs on FF2 by forcing redraw
if(dojo.isFF == 2){
var node=this.domNode;
var old = node.style.opacity;
node.style.opacity = "0.999";
this._layoutHackHandle = setTimeout(dojo.hitch(this, function(){
this._layoutHackHandle = null;
node.style.opacity = old;
}), 0);
}
}
});
dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget,
{
/*
Summary:
_FormValueWidget's correspond to native HTML elements such as <input> or <select> that have user changeable values.
Each _ValueWidget represents a single input value, and has a (possibly hidden) <input> element,
to which it serializes its input value, so that form submission (either normal submission or via FormBind?)
works as expected.
*/
attributeMap: dojo.mixin(dojo.clone(dijit.form._FormWidget.prototype.attributeMap),
{value:""}),
postCreate: function(){
if(dojo.isIE || dojo.isSafari){ // IE won't stop the event with keypress and Safari won't send an ESCAPE to keypress at all
this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown);
}
this.setValue(this.value, null);
},
setValue: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
// summary: set the value of the widget.
this.value = newValue;
this._handleOnChange(newValue, priorityChange);
},
_getValueDeprecated: false, // remove when _FormWidget:getValue is removed
getValue: function(){
// summary: get the value of the widget.
return this._lastValue;
},
undo: function(){
// summary: restore the value to the last value passed to onChange
this.setValue(this._lastValueReported, false);
},
_valueChanged: function(){
var v = this.getValue();
var lv = this._lastValueReported;
// Equality comparison of objects such as dates are done by reference so
// two distinct objects are != even if they have the same data. So use
// toStrings in case the values are objects.
return ((v !== null && (v !== undefined) && v.toString)?v.toString():'') !== ((lv !== null && (lv !== undefined) && lv.toString)?lv.toString():'');
},
_onKeyDown: function(e){
if(e.keyCode == dojo.keys.ESCAPE && !e.ctrlKey && !e.altKey){
var te;
if(dojo.isIE){
e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
te = document.createEventObject();
te.keyCode = dojo.keys.ESCAPE;
te.shiftKey = e.shiftKey;
e.srcElement.fireEvent('onkeypress', te);
}else if(dojo.isSafari){ // ESCAPE needs help making it into keypress
te = document.createEvent('Events');
te.initEvent('keypress', true, true);
te.keyCode = dojo.keys.ESCAPE;
te.shiftKey = e.shiftKey;
e.target.dispatchEvent(te);
}
}
},
_onKeyPress: function(e){
if(e.charOrCode == dojo.keys.ESCAPE && !e.ctrlKey && !e.altKey && this._valueChanged()){
this.undo();
dojo.stopEvent(e);
return false;
}else if(this.intermediateChanges){
var _this = this;
// the setTimeout allows the key to post to the widget input box
setTimeout(function(){ _this._handleOnChange(_this.getValue(), false); }, 0);
}
return true;
}
});