/* NAME: MD.Button AUTHOR: Ben Delaney DESCRIPTION: A class for creating and controlling user interface buttons. REQUIREMENTS: The 'text' option (see below) PROVIDES: MD.Button OPTIONS: icon: '' [string] If left empty, no icon will be inserted. This string needs to correspond to a CSS class that determines which icon will be visible. ,text: '' [string] The text of the button. ,size: null [string OR object] Can be a string of 'small' or 'large' (case insensitive) OR an object that represents an exact size, e.g., {height: [int], width: [int]}. If a string is used, it will be inserted as a CSS classname. ,id: null [string] The id property of the element. ,className: '' [string] The classname property of the element. ,classNameActive: 'Active' [string] The 'active' classname to be applied when the button's .activate() method is called. ,classNameInactive: 'Inactive' [string] The 'inactive' classname to be applied when the button's .deactivate() method is called. ,classNamePressed: 'Pressed' [string] The classname to be applied when the button is pressed down by the user (the mouseDown event). ,classNameHover: 'On' [string] The classname to be applied when the button is hovered over by the user (the mouseEnter event). Removed on the mouseLeave event. ,fitWidthToContainer: false [bool] Whether the button should occupy the full width of whatever container it inhabits. ,verticallyCenterText: false [bool] If an exact size is specified (either via the 'size' option or the 'styles' option), then whether the text will be centered vertically inside the button. (CANNOT be combined with truncateOverflowText). ,truncateOverflowText: false [bool] If an exact size is specified (either via the 'size' option or the 'styles' option), and the text of the button is wider than the button width, then whether the text will be truncated with an ellipsis (CANNOT be combined with verticallyCenterText). ,styles: {} [object] An object to pass in any specific CSS styles to the button. ,properties: {} [object] An object to pass in any properties to the button's HTML element (div). ,enableOnInit: true [bool] If true, the button will 'enable' itself upon initialization. If false, the .enable() method must be called before the button will 'do' anything. // ,onClick: function(this){} [function] Function that corresponds to it's javascript event name-equivalent. Receives this object ('this') as a parameter. // ,onMouseenter: function(this){} [function] Function that corresponds to it's javascript event name-equivalent. Receives this object ('this') as a parameter. // ,onMouseleave: function(this){} [function] Function that corresponds to it's javascript event name-equivalent. Receives this object ('this') as a parameter. // ,onMousedown: function(this){} [function] Function that corresponds to it's javascript event name-equivalent. Receives this object ('this') as a parameter. // ,onMouseup: function(this){} [function] Function that corresponds to it's javascript event name-equivalent. Receives this object ('this') as a parameter. METHODS: .enable([actionFunction, [arguments]]) .disable() .activate(optionalClassName) .deactivate(optionalClassName) .addClass(className) .removeClass(className) .isActive() returns a boolean which reflects the value of this.active. .isEnabled() returns a boolean which reflects the value of this.enabled. .isDisabled() returns a boolean which reflects the value of this.disabled. .setText(text) sets the text of the button. .setAction(actionFunction[, [arguments]]) sets or overrides the onClick function. .destroy() .toElement() returns the value of this.button, which is the main HTML element. RETURNS: An object with all methods and properties ready for use. To use the button, it must be inserted into the DOM either via the .toElement() method. HOW TO USE: new MD.Button([options]); EXAMPLE: var myButton = new MD.Button({ icon: 'Edit' ,text: 'Edit' ,className: 'StudentEditButton' ,styles: { top: 15 ,left: 15 } ,onClick: function(this){ alert('Do the edit'); } }); $('AnotherElement').grab(myButton.toElement()); -- OR -- var myButton = new MD.Button({[options]}).toElement(); $('AnotherElement').grab(myButton); -- OR -- var myButton = new MD.Button({[options]}); $(myButton).inject(ParentElement); */ MD.Button = new Class({ Implements: [Options,Events] ,options: { icon: '' ,text: '' ,size: null ,id: '' ,className: '' ,classNameActive: 'Active' ,classNameInactive: 'Inactive' ,classNamePressed: 'Pressed' ,classNameHover: 'On' ,fitWidthToContainer: false ,verticallyCenterText: false ,truncateOverflowText: false ,styles: {} ,properties: {} ,enableOnInit: true // ,onClick: function(clickEvent, this){} // ,onMouseenter: function(buttonObj){} // ,onMouseleave: function(buttonObj){} // ,onMousedown: function(buttonObj){} // ,onMouseup: function(buttonObj){} } ,initialize: function(options){ this.setOptions(options); this.active = false; // set the value of this.size - either a string or object if (this.options.size) { switch (typeOf(this.options.size)){ case 'string': this.size = this.sizeClassName = this.options.size.titleize(); break; case 'object': this.size = this.options.size; break; } } ///////////////////////////////// // Build the button this.button = new Element('div').grab( this.buttonInner = new Element('span').grab( this.buttonText = new Element('span', {'html':this.options.text}) ) ); // Set up the css classnames to be used... if (this.options.properties != {}) this.button.setProperties(this.options.properties); var classNames = 'MDButton'; classNames += (this.options.className != '' ? ' '+this.options.className : ''); classNames += (this.sizeClassName ? ' Size-'+this.sizeClassName : ''); classNames += (this.button.get('class') != '' ? ' '+this.button.get('class') : ''); this.button.setProperty('class', classNames); // Set various properties of the button if (this.options.id != '') this.button.setProperty('id',this.options.id); if (this.options.styles != {}) this.button.setStyles(this.options.styles); if (typeOf(this.size) == 'object') this.button.setStyles(this.size); if (this.options.fitWidthToContainer) this.button.setStyle('width', '100%'); if (this.options.verticallyCenterText) this.button.addClass('VerticallyCenter'); if (this.options.truncateOverflowText) this.button.addClass('TruncateText'); if (this.options.icon != '') { this.button.setProperty('icon', this.options.icon); this.button.addClass(this.options.icon); this.buttonInner.grab( this.icon = new Element('div.Icon', {html:' '}), 'top' ); } this.options.enableOnInit ? this.enable() : this.disable(); return (this.options.returnHTML ? this.button : this); } ,enable: function(actionFunction, args){ this.button.removeEvents(); // just in case this.button.addEvents({ click: function(e){ e.stop(); }.bind(this) ,mouseenter: function(e){ this.button.addClass('Over'); this.fireEvent('mouseenter', this); }.bind(this) ,mouseleave: function(e){ this.button.removeClass('Over'); if (this.mousedown) this.deactivate(); this.fireEvent('mouseleave', this); }.bind(this) ,mousedown: function(e){ this.mousedown = true; this.button.addClass(this.options.classNamePressed); this.fireEvent('mousedown', this); }.bind(this) ,mouseup: function(e){ this.mousedown = false; this.button.removeClass(this.options.classNamePressed); if (actionFunction) { var _arguments = []; if (args) { if (typeOf(args) == 'array') { _arguments = args; _arguments.unshift(e, this); } else { _arguments[0] = args; } } actionFunction.apply(this, _arguments); } else { this.fireEvent('mouseup', this); this.fireEvent('click', [e, this]); } }.bind(this) ,focus: function(e){ this.button.addClass(this.options.classNameHover); }.bind(this) ,blur: function(e){ this.button.removeClass(this.options.classNameHover); }.bind(this) ,selectstart: function(){ return false; } }); this.button.addClass('Enabled'); this.button.removeClass('Disabled'); this.button.setStyle('cursor', 'pointer'); this.enabled = true; this.disabled = false; return this; } ,disable: function(){ this.button.removeEvents(); this.button.addClass('Disabled'); this.button.removeClass('Enabled'); this.button.setStyle('cursor', 'default'); this.enabled = false; this.disabled = true; return this; } ,activate: function(optionalClassName){ // remove the inactive class... this.button.removeClass((this.inactiveClassOverride ? this.inactiveClassOverride : this.options.classNameInactive)); // add the active class... if (optionalClassName) this.activeClassOverride = optionalClassName; this.button.addClass((optionalClassName ? this.activeClassOverride : this.options.classNameActive)); this.active = true; return this; } ,deactivate: function(optionalClassName){ // remove the active class this.button.removeClass((this.activeClassOverride ? this.activeClassOverride : this.options.classNameActive)); // add the inactive class if (optionalClassName) this.inactiveClassOverride = optionalClassName; this.button.addClass((optionalClassName ? this.inactiveClassOverride : this.options.classNameInactive)); this.button.removeClass(this.options.classNamePressed); this.active = false; return this; } ,addClass: function(className){ if (!className) { throw new Error('No className passed to the addClass method of MD.Button'); return; } else { this.button.addClass(className); } return this; } ,removeClass: function(className){ if (!className) { throw new Error('No className passed to the removeClass method of MD.Button'); return; } else { this.button.removeClass(className); } return this; } ,hasClass: function(className) { return this.button.hasClass(className); } ,isActive: function(){ return this.active; } ,isEnabled: function(){ return this.enabled; } ,isDisabled: function(){ return this.disabled; } ,setText: function(newText){ this.buttonText.empty().setProperty('text', newText); return this; } ,setAction: function(actionFunction, argumentsArray){ this.activate(actionFunction, argumentsArray); return this; } ,destroy: function(){ this.button.destroy(); return this; } ,toElement: function(){ return this.button; } });