Skip to content

Commit

Permalink
Make a bunch of tweaks to S2.UI.Button to support new button types …
Browse files Browse the repository at this point in the history
…(radio button, checkbox, link, etc.).
  • Loading branch information
savetheclocktower committed Apr 5, 2010
1 parent 70e0357 commit 2a3a136
Showing 1 changed file with 142 additions and 37 deletions.
179 changes: 142 additions & 37 deletions src/ui/controls/button.js
Expand Up @@ -5,47 +5,168 @@
*
* Applies button-like behavior to an element.
**/
UI.Button = Class.create(UI.Base, {
UI.Button = Class.create(UI.Base, UI.Mixin.Element, {
NAME: "S2.UI.Button",

/**
* new S2.UI.Button(element, options)
**/
initialize: function(element, options) {
this.element = $(element);
this.element.store('ui.button', this);
var opt = this.setOptions(options);

UI.addClassNames(this.element, 'ui-state-default ui-corner-all');
UI.addBehavior(this.element, [UI.Behavior.Hover, UI.Behavior.Focus,
UI.Behavior.Down]);

if (opt.primary) {
this.element.addClassName('ui-priority-primary');
var name = this.element.nodeName.toUpperCase(), type;

// Assign a type to the button.
if (name === 'INPUT') {
type = this.element.type;
if (type === 'checkbox' || type === 'radio') {
this.type = this.element.type;
} else {
this.type = 'input';
}
} else {
this.type = 'button';
}

var opt = this.setOptions(options);

// ARIA
this.element.writeAttribute('role', 'button');
// For checkboxes and radio buttons, the label acts as the visual
// representation of the control, and receives all interactions.
if (this._isCheckboxOrRadio()) {
this._handleFormWidget();
} else {
this._makeButtonElement(this.element);
}

this.element.store('ui.button', this);
if (this._buttonElement !== this.element) {
this._buttonElement.store('ui.button', this);
}

this.enabled = true;
var enabled = (this.element.disabled === true) ||
!this.element.hasClassName('ui-state-disabled');
var enabled = (this._buttonElement.disabled === true) ||
!this._buttonElement.hasClassName('ui-state-disabled');

this.setEnabled(enabled);

this.observers = {
click: this._click.bind(this),
keydown: this._keydown.bind(this)
};
this.addObservers();
},

addObservers: function() {
this.observe('click', this.observers.click);
this.observe('keydown', this.observers.keydown);
},

removeObservers: function() {
this.stopObserving('click', this.observers.click);
this.stopObserving('keydown', this.observers.keydown);
},

isActive: function() {
if (!this._isToggleButton()) return false;
return this.hasClassName('ui-state-active');
},

_setActive: function(bool) {
this[bool ? 'addClassName' : 'removeClassName']('ui-state-active');
},

toggle: function(bool) {
if (!this._isToggleButton()) return;

var isActive = this.isActive();
if (Object.isUndefined(bool)) bool = !isActive;

var willChange = (bool !== isActive);
if (willChange) {
var result = this.toElement().fire('ui:button:toggle');
if (result.stopped) return;
}
this._buttonElement[bool ? 'addClassName' : 'removeClassName']('ui-state-active');
},

_click: function(event) {
this.toggle();
},

_keydown: function(event) {
var code = event.keyCode;
if (code !== Event.KEY_SPACE && code !== Event.KEY_RETURN)
return;

this.toggle();
this.element.checked = this.isActive();
},

_isCheckboxOrRadio: function() {
return this.type === 'checkbox' || this.type === 'radio';
},

_isToggleButton: function() {
return this._isCheckboxOrRadio() || this.options.toggle;
},

_makeButtonElement: function(element) {
this._buttonElement = element;

var opt = this.options;
UI.addClassNames(element,
'ui-button ui-widget ui-state-default ui-corner-all');

var B = UI.Behavior, behaviors = [B.Hover, B.Focus, B.Down];
UI.addBehavior(element, behaviors);

if (opt.primary) {
element.addClassName('ui-priority-primary');
}

if (opt.label === null) {
opt.label = element.innerHTML || element.value;
}

// ARIA.
element.writeAttribute('role', 'button');
},

_handleFormWidget: function() {
var opt = this.options;
// First, find the label.
var id = this.element.id, label;
if (id) {
label = $$('label[for="' + id + '"]')[0];
}
if (!label) {
// The form widget might be wrapped in an implicit label.
label = this.element.up('label');
}

if (!label) {
opt.label = null;
return;
}

this.element.addClassName('ui-helper-hidden-accessible');
this._makeButtonElement(label);
UI.makeFocusable(label, true);
this.label = label;
},

/**
* S2.UI.Button#setEnabled(isEnabled) -> this
* - isEnabled (Boolean): Whether the button should be enabled.
**/

setEnabled: function(isEnabled) {
var element = this._buttonElement;
if (this.enabled === isEnabled) return;
this.enabled = isEnabled;
if (isEnabled) {
this.element.removeClassName('ui-state-disabled');
element.removeClassName('ui-state-disabled');
} else {
this.element.addClassName('ui-state-disabled');
element.addClassName('ui-state-disabled');
}
this.element.disabled = !isEnabled;
},
Expand All @@ -58,35 +179,19 @@
* `Element#insert`.
**/
toElement: function() {
return this.element;
},

/**
* S2.UI.toHTML() -> String
*
* Returns the HTML of the instance's element.
**/
toHTML: function() {
return this.element.toHTML();
},

/**
* S2.UI.toString() -> String
*
* Returns the HTML of the instance's element.
**/
toString: function() {
return this.element.toHTML();
return this._buttonElement;
},

inspect: function() {
return this.element.inspect();
return this.toElement().inspect();
}
});

Object.extend(UI.Button, {
DEFAULT_OPTIONS: {
primary: false
primary: false,
label: null,
toggle: false
}
});

Expand Down

0 comments on commit 2a3a136

Please sign in to comment.