Yahoo! UI Library > datatable > CellEditor.js (source view)
(function () {
var lang = YAHOO.lang,
util = YAHOO.util,
widget = YAHOO.widget,
ua = YAHOO.env.ua,
Dom = util.Dom,
Ev = util.Event,
DT = widget.DataTable;
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* The BaseCellEditor class provides base functionality common to all inline cell
* editors for a DataTable widget.
*
* @namespace YAHOO.widget
* @class BaseCellEditor
* @uses YAHOO.util.EventProvider
* @constructor
* @param sType {String} Type indicator, to map to YAHOO.widget.DataTable.Editors.
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.BaseCellEditor = function(sType, oConfigs) {
this._sId = this._sId || "yui-ceditor" + YAHOO.widget.BaseCellEditor._nCount++;
this._sType = sType;
// Validate inputs
this._initConfigs(oConfigs);
// Create Custom Events
this._initEvents();
// Draw UI
this.render();
};
var BCE = widget.BaseCellEditor;
/////////////////////////////////////////////////////////////////////////////
//
// Static members
//
/////////////////////////////////////////////////////////////////////////////
lang.augmentObject(BCE, {
/**
* Global instance counter.
*
* @property CellEditor._nCount
* @type Number
* @static
* @default 0
* @private
*/
_nCount : 0,
/**
* Class applied to CellEditor container.
*
* @property CellEditor.CLASS_CELLEDITOR
* @type String
* @static
* @default "yui-ceditor"
*/
CLASS_CELLEDITOR : "yui-ceditor"
});
BCE.prototype = {
/////////////////////////////////////////////////////////////////////////////
//
// Private members
//
/////////////////////////////////////////////////////////////////////////////
/**
* Unique id assigned to instance "yui-ceditorN", useful prefix for generating unique
* DOM ID strings and log messages.
*
* @property _sId
* @type String
* @private
*/
_sId : null,
/**
* Editor type.
*
* @property _sType
* @type String
* @private
*/
_sType : null,
/**
* DataTable instance.
*
* @property _oDataTable
* @type YAHOO.widget.DataTable
* @private
*/
_oDataTable : null,
/**
* Column instance.
*
* @property _oColumn
* @type YAHOO.widget.Column
* @default null
*/
_oColumn : null,
/**
* Record instance.
*
* @property _oRecord
* @type YAHOO.widget.Record
* @default null
* @private
*/
_oRecord : null,
/**
* TD element.
*
* @property _elTd
* @type HTMLElement
* @default null
* @private
*/
_elTd : null,
/**
* Container for inline editor.
*
* @property _elContainer
* @type HTMLElement
* @private
*/
_elContainer : null,
/**
* Reference to Cancel button, if available.
*
* @property _elCancelBtn
* @type HTMLElement
* @default null
* @private
*/
_elCancelBtn : null,
/**
* Reference to Save button, if available.
*
* @property _elSaveBtn
* @type HTMLElement
* @default null
* @private
*/
_elSaveBtn : null,
/////////////////////////////////////////////////////////////////////////////
//
// Private methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* Initialize configs.
*
* @method _initConfigs
* @private
*/
_initConfigs : function(oConfigs) {
// Object literal defines CellEditor configs
if(oConfigs && YAHOO.lang.isObject(oConfigs)) {
for(var sConfig in oConfigs) {
if(sConfig) {
this[sConfig] = oConfigs[sConfig];
}
}
}
},
/**
* Initialize Custom Events.
*
* @method _initEvents
* @private
*/
_initEvents : function() {
this.createEvent("showEvent");
this.createEvent("keydownEvent");
this.createEvent("invalidDataEvent");
this.createEvent("revertEvent");
this.createEvent("saveEvent");
this.createEvent("cancelEvent");
this.createEvent("blurEvent");
this.createEvent("blockEvent");
this.createEvent("unblockEvent");
},
/////////////////////////////////////////////////////////////////////////////
//
// Public properties
//
/////////////////////////////////////////////////////////////////////////////
/**
* Implementer defined function that can submit the input value to a server. This
* function must accept the arguments fnCallback and oNewValue. When the submission
* is complete, the function must also call fnCallback(bSuccess, oNewValue) to
* finish the save routine in the CellEditor. This function can also be used to
* perform extra validation or input value manipulation.
*
* @property asyncSubmitter
* @type HTMLFunction
*/
asyncSubmitter : null,
/**
* Current value.
*
* @property value
* @type MIXED
*/
value : null,
/**
* Default value in case Record data is undefined. NB: Null values will not trigger
* the default value.
*
* @property defaultValue
* @type MIXED
* @default null
*/
defaultValue : null,
/**
* Validator function for input data, called from the DataTable instance scope,
* receives the arguments (inputValue, currentValue, editorInstance) and returns
* either the validated (or type-converted) value or undefined.
*
* @property validator
* @type HTMLFunction
* @default null
*/
validator : null,
/**
* True if currently active.
*
* @property isActive
* @type Boolean
*/
isActive : false,
/**
* Text to display on Save button.
*
* @property LABEL_SAVE
* @type String
* @default "Save"
*/
LABEL_SAVE : "Save",
/**
* Text to display on Cancel button.
*
* @property LABEL_CANCEL
* @type String
* @default "Cancel"
*/
LABEL_CANCEL : "Cancel",
/**
* True if Save/Cancel buttons should not be displayed in the CellEditor.
*
* @property disableBtns
* @type Boolean
* @default false
*/
disableBtns : false,
/////////////////////////////////////////////////////////////////////////////
//
// Public methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* CellEditor instance name, for logging.
*
* @method toString
* @return {String} Unique name of the CellEditor instance.
*/
toString : function() {
return "CellEditor instance " + this._sId;
},
/**
* CellEditor unique ID.
*
* @method getId
* @return {String} Unique ID of the CellEditor instance.
*/
getId : function() {
return this._sId;
},
/**
* Returns reference to associated DataTable instance.
*
* @method getDataTable
* @return {YAHOO.widget.DataTable} DataTable instance.
*/
getDataTable : function() {
return this._oDataTable;
},
/**
* Returns reference to associated Column instance.
*
* @method getColumn
* @return {YAHOO.widget.Column} Column instance.
*/
getColumn : function() {
return this._oColumn;
},
/**
* Returns reference to associated Record instance.
*
* @method getRecord
* @return {YAHOO.widget.Record} Record instance.
*/
getRecord : function() {
return this._oRecord;
},
/**
* Returns reference to associated TD element.
*
* @method getTdEl
* @return {HTMLElement} TD element.
*/
getTdEl : function() {
return this._elTd;
},
/**
* Returns container element.
*
* @method getContainerEl
* @return {HTMLElement} Reference to container element.
*/
getContainerEl : function() {
return this._elContainer;
},
/**
* Nulls out the entire CellEditor instance and related objects, removes attached
* event listeners, and clears out DOM elements inside the container, removes
* container from the DOM.
*
* @method destroy
*/
destroy : function() {
this.unsubscribeAll();
// Column is late-binding in attach()
var oColumn = this.getColumn();
if(oColumn) {
this.getColumn().editor = null;
}
var elContainer = this.getContainerEl();
Ev.purgeElement(elContainer, true);
elContainer.parentNode.removeChild(elContainer);
},
/**
* Renders DOM elements and attaches event listeners.
*
* @method render
*/
render : function() {
// Render Cell Editor container element as first child of body
var elContainer = document.createElement("div");
elContainer.id = this.getId() + "-container"; // Needed for tracking blur event
elContainer.style.display = "none";
elContainer.tabIndex = 0;
elContainer.className = DT.CLASS_EDITOR;
document.body.insertBefore(elContainer, document.body.firstChild);
this._elContainer = elContainer;
// Handle ESC key
Ev.addListener(elContainer, "keydown", function(e, oSelf) {
// ESC cancels Cell Editor
if((e.keyCode == 27)) {
oSelf.cancel();
}
// Pass through event
oSelf.fireEvent("keydownEvent", {editor:this, event:e});
}, this);
this.renderForm();
// Show Save/Cancel buttons
if(!this.disableBtns) {
this.renderBtns();
}
this.doAfterRender();
},
/**
* Renders Save/Cancel buttons.
*
* @method renderBtns
*/
renderBtns : function() {
// Buttons
var elBtnsDiv = this.getContainerEl().appendChild(document.createElement("div"));
elBtnsDiv.className = DT.CLASS_BUTTON;
// Save button
var elSaveBtn = elBtnsDiv.appendChild(document.createElement("button"));
elSaveBtn.className = DT.CLASS_DEFAULT;
elSaveBtn.innerHTML = this.LABEL_SAVE;
Ev.addListener(elSaveBtn, "click", function(oArgs) {
this.save();
}, this, true);
this._elSaveBtn = elSaveBtn;
// Cancel button
var elCancelBtn = elBtnsDiv.appendChild(document.createElement("button"));
elCancelBtn.innerHTML = this.LABEL_CANCEL;
Ev.addListener(elCancelBtn, "click", function(oArgs) {
this.cancel();
}, this, true);
this._elCancelBtn = elCancelBtn;
},
/**
* Attach CellEditor for a new interaction.
*
* @method attach
* @param oDataTable {YAHOO.widget.DataTable} Associated DataTable instance.
* @param elCell {HTMLElement} Cell to edit.
*/
attach : function(oDataTable, elCell) {
// Validate
if(oDataTable instanceof YAHOO.widget.DataTable) {
this._oDataTable = oDataTable;
// Validate cell
elCell = oDataTable.getTdEl(elCell);
if(elCell) {
this._elTd = elCell;
// Validate Column
var oColumn = oDataTable.getColumn(elCell);
if(oColumn) {
this._oColumn = oColumn;
// Validate Record
var oRecord = oDataTable.getRecord(elCell);
if(oRecord) {
this._oRecord = oRecord;
var value = oRecord.getData(this.getColumn().getKey());
this.value = (value !== undefined) ? value : this.defaultValue;
return true;
}
}
}
}
YAHOO.log("Could not attach CellEditor","error",this.toString());
return false;
},
/**
* Moves container into position for display.
*
* @method move
*/
move : function() {
// Move Editor
var elContainer = this.getContainerEl(),
elTd = this.getTdEl(),
x = Dom.getX(elTd),
y = Dom.getY(elTd);
//TODO: remove scrolling logic
// SF doesn't get xy for cells in scrolling table
// when tbody display is set to block
if(isNaN(x) || isNaN(y)) {
var elTbody = this.getDataTable().getTbodyEl();
x = elTd.offsetLeft + // cell pos relative to table
Dom.getX(elTbody.parentNode) - // plus table pos relative to document
elTbody.scrollLeft; // minus tbody scroll
y = elTd.offsetTop + // cell pos relative to table
Dom.getY(elTbody.parentNode) - // plus table pos relative to document
elTbody.scrollTop + // minus tbody scroll
this.getDataTable().getTheadEl().offsetHeight; // account for fixed THEAD cells
}
elContainer.style.left = x + "px";
elContainer.style.top = y + "px";
},
/**
* Displays CellEditor UI in the correct position.
*
* @method show
*/
show : function() {
this.resetForm();
this.isActive = true;
this.getContainerEl().style.display = "";
this.focus();
this.fireEvent("showEvent", {editor:this});
YAHOO.log("CellEditor shown", "info", this.toString());
},
/**
* Fires blockEvent
*
* @method block
*/
block : function() {
this.fireEvent("blockEvent", {editor:this});
YAHOO.log("CellEditor blocked", "info", this.toString());
},
/**
* Fires unblockEvent
*
* @method unblock
*/
unblock : function() {
this.fireEvent("unblockEvent", {editor:this});
YAHOO.log("CellEditor unblocked", "info", this.toString());
},
/**
* Saves value of CellEditor and hides UI.
*
* @method save
*/
save : function() {
// Get new value
var inputValue = this.getInputValue();
var validValue = inputValue;
// Validate new value
if(this.validator) {
validValue = this.validator.call(this.getDataTable(), inputValue, this.value, this);
if(validValue === undefined ) {
this.resetForm();
this.fireEvent("invalidDataEvent",
{editor:this, oldData:this.value, newData:inputValue});
YAHOO.log("Could not save Cell Editor input due to invalid data " +
lang.dump(inputValue), "warn", this.toString());
return;
}
}
var oSelf = this;
var finishSave = function(bSuccess, oNewValue) {
var oOrigValue = YAHOO.widget.DataTable._cloneObject(oSelf.value);
if(bSuccess) {
// Update new value
oSelf.value = oNewValue;
oSelf.getDataTable().updateCell(oSelf.getRecord(), oSelf.getColumn(), oNewValue);
// Hide CellEditor
oSelf.getContainerEl().style.display = "none";
oSelf.isActive = false;
oSelf.getDataTable()._oCellEditor = null;
oSelf.fireEvent("saveEvent",
{editor:oSelf, oldData:oOrigValue, newData:oSelf.value});
YAHOO.log("Cell Editor input saved", "info", this.toString());
}
else {
oSelf.resetForm();
oSelf.fireEvent("revertEvent",
{editor:oSelf, oldData:oOrigValue, newData:oNewValue});
YAHOO.log("Could not save Cell Editor input " +
lang.dump(oNewValue), "warn", oSelf.toString());
}
oSelf.unblock();
};
this.block();
if(lang.isFunction(this.asyncSubmitter)) {
this.asyncSubmitter.call(this, finishSave, validValue);
}
else {
finishSave(true, validValue);
}
},
/**
* Cancels CellEditor input and hides UI.
*
* @method cancel
*/
cancel : function() {
if(this.isActive) {
this.getContainerEl().style.display = "none";
this.isActive = false;
this.getDataTable._oCellEditor = null;
this.fireEvent("cancelEvent", {editor:this});
YAHOO.log("CellEditor canceled", "info", this.toString());
}
else {
YAHOO.log("Unable to cancel CellEditor", "warn", this.toString());
}
},
/**
* Renders form elements.
*
* @method renderForm
*/
renderForm : function() {
// To be implemented by subclass
},
/**
* Access to add additional event listeners.
*
* @method doAfterRender
*/
doAfterRender : function() {
// To be implemented by subclass
},
/**
* After rendering form, if disabledBtns is set to true, then sets up a mechanism
* to save input without them.
*
* @method handleDisabledBtns
*/
handleDisabledBtns : function() {
// To be implemented by subclass
},
/**
* Resets CellEditor UI to initial state.
*
* @method resetForm
*/
resetForm : function() {
// To be implemented by subclass
},
/**
* Sets focus in CellEditor.
*
* @method focus
*/
focus : function() {
// To be implemented by subclass
},
/**
* Retrieves input value from CellEditor.
*
* @method getInputValue
*/
getInputValue : function() {
// To be implemented by subclass
}
};
lang.augmentProto(BCE, util.EventProvider);
/////////////////////////////////////////////////////////////////////////////
//
// Custom Events
//
/////////////////////////////////////////////////////////////////////////////
/**
* Fired when a CellEditor is shown.
*
* @event showEvent
* @param oArgs.editor {YAHOO.widget.CellEditor} The CellEditor instance.
*/
/**
* Fired when a CellEditor has a keydown.
*
* @event keydownEvent
* @param oArgs.editor {YAHOO.widget.CellEditor} The CellEditor instance.
* @param oArgs.event {HTMLEvent} The event object.
*/
/**
* Fired when a CellEditor input is reverted due to invalid data.
*
* @event invalidDataEvent
* @param oArgs.editor {YAHOO.widget.CellEditor} The CellEditor instance.
* @param oArgs.newData {Object} New data value from form input field.
* @param oArgs.oldData {Object} Old data value.
*/
/**
* Fired when a CellEditor input is reverted due to asyncSubmitter failure.
*
* @event revertEvent
* @param oArgs.editor {YAHOO.widget.CellEditor} The CellEditor instance.
* @param oArgs.newData {Object} New data value from form input field.
* @param oArgs.oldData {Object} Old data value.
*/
/**
* Fired when a CellEditor input is saved.
*
* @event saveEvent
* @param oArgs.editor {YAHOO.widget.CellEditor} The CellEditor instance.
* @param oArgs.newData {Object} New data value from form input field.
* @param oArgs.oldData {Object} Old data value.
*/
/**
* Fired when a CellEditor input is canceled.
*
* @event cancelEvent
* @param oArgs.editor {YAHOO.widget.CellEditor} The CellEditor instance.
*/
/**
* Fired when a CellEditor has a blur event.
*
* @event blurEvent
* @param oArgs.editor {YAHOO.widget.CellEditor} The CellEditor instance.
*/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* The CheckboxCellEditor class provides functionality for inline editing
* DataTable cell data with checkboxes.
*
* @namespace YAHOO.widget
* @class CheckboxCellEditor
* @extends YAHOO.widget.BaseCellEditor
* @constructor
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.CheckboxCellEditor = function(oConfigs) {
this._sId = "yui-checkboxceditor" + YAHOO.widget.BaseCellEditor._nCount++;
widget.CheckboxCellEditor.superclass.constructor.call(this, "checkbox", oConfigs);
};
// CheckboxCellEditor extends BaseCellEditor
lang.extend(widget.CheckboxCellEditor, BCE, {
/////////////////////////////////////////////////////////////////////////////
//
// CheckboxCellEditor public properties
//
/////////////////////////////////////////////////////////////////////////////
/**
* Array of checkbox values. Can either be a simple array (e.g., ["red","green","blue"])
* or a an array of objects (e.g., [{label:"red", value:"#FF0000"},
* {label:"green", value:"#00FF00"}, {label:"blue", value:"#0000FF"}]).
*
* @property checkboxOptions
* @type String[] | Object[]
*/
checkboxOptions : null,
/**
* Reference to the checkbox elements.
*
* @property checkboxes
* @type HTMLElement[]
*/
checkboxes : null,
/**
* Array of checked values
*
* @property value
* @type String[]
*/
value : null,
/////////////////////////////////////////////////////////////////////////////
//
// CheckboxCellEditor public methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* Render a form with input(s) type=checkbox.
*
* @method renderForm
*/
renderForm : function() {
if(lang.isArray(this.checkboxOptions)) {
var checkboxOption, checkboxValue, checkboxId, elLabel, j, len;
// Create the checkbox buttons in an IE-friendly way...
for(j=0,len=this.checkboxOptions.length; j<len; j++) {
checkboxOption = this.checkboxOptions[j];
checkboxValue = lang.isValue(checkboxOption.value) ?
checkboxOption.value : checkboxOption;
checkboxId = this.getId() + "-chk" + j;
this.getContainerEl().innerHTML += "<input type=\"checkbox\"" +
" id=\"" + checkboxId + "\"" + // Needed for label
" value=\"" + checkboxValue + "\" />";
// Create the labels in an IE-friendly way
elLabel = this.getContainerEl().appendChild(document.createElement("label"));
elLabel.htmlFor = checkboxId;
elLabel.innerHTML = lang.isValue(checkboxOption.label) ?
checkboxOption.label : checkboxOption;
}
// Store the reference to the checkbox elements
var allCheckboxes = [];
for(j=0; j<len; j++) {
allCheckboxes[allCheckboxes.length] = this.getContainerEl().childNodes[j*2];
}
this.checkboxes = allCheckboxes;
if(this.disableBtns) {
this.handleDisabledBtns();
}
}
else {
YAHOO.log("Could not find checkboxOptions", "error", this.toString());
}
},
/**
* After rendering form, if disabledBtns is set to true, then sets up a mechanism
* to save input without them.
*
* @method handleDisabledBtns
*/
handleDisabledBtns : function() {
Ev.addListener(this.getContainerEl(), "click", function(v){
if(Ev.getTarget(v).tagName.toLowerCase() === "input") {
// Save on blur
this.save();
}
}, this, true);
},
/**
* Resets CheckboxCellEditor UI to initial state.
*
* @method resetForm
*/
resetForm : function() {
// Normalize to array
var originalValues = lang.isArray(this.value) ? this.value : [this.value];
// Match checks to value
for(var i=0, j=this.checkboxes.length; i<j; i++) {
this.checkboxes[i].checked = false;
for(var k=0, len=originalValues.length; k<len; k++) {
if(this.checkboxes[i].value === originalValues[k]) {
this.checkboxes[i].checked = true;
}
}
}
},
/**
* Sets focus in CheckboxCellEditor.
*
* @method focus
*/
focus : function() {
this.checkboxes[0].focus();
},
/**
* Retrieves input value from CheckboxCellEditor.
*
* @method getInputValue
*/
getInputValue : function() {
var checkedValues = [];
for(var i=0, j=this.checkboxes.length; i<j; i++) {
if(this.checkboxes[i].checked) {
checkedValues[checkedValues.length] = this.checkboxes[i].value;
}
}
return checkedValues;
}
});
// Copy static members to CheckboxCellEditor class
lang.augmentObject(widget.CheckboxCellEditor, BCE);
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* The DataCellEditor class provides functionality for inline editing
* DataTable cell data with a YUI Calendar.
*
* @namespace YAHOO.widget
* @class DateCellEditor
* @extends YAHOO.widget.BaseCellEditor
* @constructor
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.DateCellEditor = function(oConfigs) {
this._sId = "yui-dateceditor" + YAHOO.widget.BaseCellEditor._nCount++;
widget.DateCellEditor.superclass.constructor.call(this, "date", oConfigs);
};
// CheckboxCellEditor extends BaseCellEditor
lang.extend(widget.DateCellEditor, BCE, {
/////////////////////////////////////////////////////////////////////////////
//
// DateCellEditor public properties
//
/////////////////////////////////////////////////////////////////////////////
/**
* Reference to Calendar instance.
*
* @property calendar
* @type YAHOO.widget.Calendar
*/
calendar : null,
/**
* Default value.
*
* @property defaultValue
* @type Date
* @default new Date()
*/
defaultValue : new Date(),
/////////////////////////////////////////////////////////////////////////////
//
// DateCellEditor public methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* Render a Calendar.
*
* @method renderForm
*/
renderForm : function() {
// Calendar widget
if(YAHOO.widget.Calendar) {
var calContainer = this.getContainerEl().appendChild(document.createElement("div"));
calContainer.id = this.getId() + "-dateContainer"; // Needed for Calendar constructor
var calendar =
new YAHOO.widget.Calendar(this.getId() + "-date",
calContainer.id);
calendar.render();
calContainer.style.cssFloat = "none";
if(ua.ie) {
var calFloatClearer = this.getContainerEl().appendChild(document.createElement("br"));
calFloatClearer.style.clear = "both";
}
this.calendar = calendar;
if(this.disableBtns) {
this.handleDisabledBtns();
}
}
else {
YAHOO.log("Could not find YUI Calendar", "error", this.toString());
}
},
/**
* After rendering form, if disabledBtns is set to true, then sets up a mechanism
* to save input without them.
*
* @method handleDisabledBtns
*/
handleDisabledBtns : function() {
this.calendar.selectEvent.subscribe(function(v){
// Save on select
this.save();
}, this, true);
},
/**
* Resets DateCellEditor UI to initial state.
*
* @method resetForm
*/
resetForm : function() {
var value = this.value;
var selectedValue = (value.getMonth()+1)+"/"+value.getDate()+"/"+value.getFullYear();
this.calendar.cfg.setProperty("selected",selectedValue,false);
this.calendar.render();
},
/**
* Sets focus in DateCellEditor.
*
* @method focus
*/
focus : function() {
// To be impmlemented by subclass
},
/**
* Retrieves input value from DateCellEditor.
*
* @method getInputValue
*/
getInputValue : function() {
return this.calendar.getSelectedDates()[0];
}
});
// Copy static members to DateCellEditor class
lang.augmentObject(widget.DateCellEditor, BCE);
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* The DropdownCellEditor class provides functionality for inline editing
* DataTable cell data a SELECT element.
*
* @namespace YAHOO.widget
* @class DropdownCellEditor
* @extends YAHOO.widget.BaseCellEditor
* @constructor
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.DropdownCellEditor = function(oConfigs) {
this._sId = "yui-dropdownceditor" + YAHOO.widget.BaseCellEditor._nCount++;
widget.DropdownCellEditor.superclass.constructor.call(this, "dropdown", oConfigs);
};
// DropdownCellEditor extends BaseCellEditor
lang.extend(widget.DropdownCellEditor, BCE, {
/////////////////////////////////////////////////////////////////////////////
//
// DropdownCellEditor public properties
//
/////////////////////////////////////////////////////////////////////////////
/**
* Array of dropdown values. Can either be a simple array (e.g.,
* ["Alabama","Alaska","Arizona","Arkansas"]) or a an array of objects (e.g.,
* [{label:"Alabama", value:"AL"}, {label:"Alaska", value:"AK"},
* {label:"Arizona", value:"AZ}, {label:"Arkansas", value:"AR}]).
*
* @property dropdownOptions
* @type String[] | Object[]
*/
dropdownOptions : null,
/**
* Reference to Dropdown element.
*
* @property dropdown
* @type HTMLElement
*/
dropdown : null,
/////////////////////////////////////////////////////////////////////////////
//
// DropdownCellEditor public methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* Render a form with select element.
*
* @method renderForm
*/
renderForm : function() {
var elDropdown = this.getContainerEl().appendChild(document.createElement("select"));
elDropdown.style.zoom = 1;
this.dropdown = elDropdown;
if(lang.isArray(this.dropdownOptions)) {
var dropdownOption, elOption;
for(var i=0, j=this.dropdownOptions.length; i<j; i++) {
dropdownOption = this.dropdownOptions[i];
elOption = document.createElement("option");
elOption.value = (lang.isValue(dropdownOption.value)) ?
dropdownOption.value : dropdownOption;
elOption.innerHTML = (lang.isValue(dropdownOption.label)) ?
dropdownOption.label : dropdownOption;
elOption = elDropdown.appendChild(elOption);
}
if(this.disableBtns) {
this.handleDisabledBtns();
}
}
},
/**
* After rendering form, if disabledBtns is set to true, then sets up a mechanism
* to save input without them.
*
* @method handleDisabledBtns
*/
handleDisabledBtns : function() {
Ev.addListener(this.dropdown, "change", function(v){
// Save on change
this.save();
}, this, true);
},
/**
* Resets DropdownCellEditor UI to initial state.
*
* @method resetForm
*/
resetForm : function() {
for(var i=0, j=this.dropdown.options.length; i<j; i++) {
if(this.value === this.dropdown.options[i].value) {
this.dropdown.options[i].selected = true;
}
}
},
/**
* Sets focus in DropdownCellEditor.
*
* @method focus
*/
focus : function() {
this.getDataTable()._focusEl(this.dropdown);
},
/**
* Retrieves input value from DropdownCellEditor.
*
* @method getInputValue
*/
getInputValue : function() {
return this.dropdown.options[this.dropdown.options.selectedIndex].value;
}
});
// Copy static members to DropdownCellEditor class
lang.augmentObject(widget.DropdownCellEditor, BCE);
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* The RadioCellEditor class provides functionality for inline editing
* DataTable cell data with radio buttons.
*
* @namespace YAHOO.widget
* @class RadioCellEditor
* @extends YAHOO.widget.BaseCellEditor
* @constructor
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.RadioCellEditor = function(oConfigs) {
this._sId = "yui-radioceditor" + YAHOO.widget.BaseCellEditor._nCount++;
widget.RadioCellEditor.superclass.constructor.call(this, "radio", oConfigs);
};
// RadioCellEditor extends BaseCellEditor
lang.extend(widget.RadioCellEditor, BCE, {
/////////////////////////////////////////////////////////////////////////////
//
// RadioCellEditor public properties
//
/////////////////////////////////////////////////////////////////////////////
/**
* Reference to radio elements.
*
* @property radios
* @type HTMLElement[]
*/
radios : null,
/**
* Array of radio values. Can either be a simple array (e.g., ["yes","no","maybe"])
* or a an array of objects (e.g., [{label:"yes", value:1}, {label:"no", value:-1},
* {label:"maybe", value:0}]).
*
* @property radioOptions
* @type String[] | Object[]
*/
radioOptions : null,
/////////////////////////////////////////////////////////////////////////////
//
// RadioCellEditor public methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* Render a form with input(s) type=radio.
*
* @method renderForm
*/
renderForm : function() {
if(lang.isArray(this.radioOptions)) {
var radioOption, radioValue, radioId, elLabel;
// Create the radio buttons in an IE-friendly way
for(var i=0, len=this.radioOptions.length; i<len; i++) {
radioOption = this.radioOptions[i];
radioValue = lang.isValue(radioOption.value) ?
radioOption.value : radioOption;
radioId = this.getId() + "-radio" + i;
this.getContainerEl().innerHTML += "<input type=\"radio\"" +
" name=\"" + this.getId() + "\"" +
" value=\"" + radioValue + "\"" +
" id=\"" + radioId + "\" />"; // Needed for label
// Create the labels in an IE-friendly way
elLabel = this.getContainerEl().appendChild(document.createElement("label"));
elLabel.htmlFor = radioId;
elLabel.innerHTML = (lang.isValue(radioOption.label)) ?
radioOption.label : radioOption;
}
// Store the reference to the checkbox elements
var allRadios = [],
elRadio;
for(var j=0; j<len; j++) {
elRadio = this.getContainerEl().childNodes[j*2];
allRadios[allRadios.length] = elRadio;
}
this.radios = allRadios;
if(this.disableBtns) {
this.handleDisabledBtns();
}
}
else {
YAHOO.log("Could not find radioOptions", "error", this.toString());
}
},
/**
* After rendering form, if disabledBtns is set to true, then sets up a mechanism
* to save input without them.
*
* @method handleDisabledBtns
*/
handleDisabledBtns : function() {
Ev.addListener(this.getContainerEl(), "click", function(v){
if(Ev.getTarget(v).tagName.toLowerCase() === "input") {
// Save on blur
this.save();
}
}, this, true);
},
/**
* Resets RadioCellEditor UI to initial state.
*
* @method resetForm
*/
resetForm : function() {
for(var i=0, j=this.radios.length; i<j; i++) {
var elRadio = this.radios[i];
if(this.value === elRadio.value) {
elRadio.checked = true;
return;
}
}
},
/**
* Sets focus in RadioCellEditor.
*
* @method focus
*/
focus : function() {
for(var i=0, j=this.radios.length; i<j; i++) {
if(this.radios[i].checked) {
this.radios[i].focus();
return;
}
}
},
/**
* Retrieves input value from RadioCellEditor.
*
* @method getInputValue
*/
getInputValue : function() {
for(var i=0, j=this.radios.length; i<j; i++) {
if(this.radios[i].checked) {
return this.radios[i].value;
}
}
}
});
// Copy static members to RadioCellEditor class
lang.augmentObject(widget.RadioCellEditor, BCE);
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* The TextareaCellEditor class provides functionality for inline editing
* DataTable cell data with a TEXTAREA element.
*
* @namespace YAHOO.widget
* @class TextareaCellEditor
* @extends YAHOO.widget.BaseCellEditor
* @constructor
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.TextareaCellEditor = function(oConfigs) {
this._sId = "yui-textareaceditor" + YAHOO.widget.BaseCellEditor._nCount++;
widget.TextareaCellEditor.superclass.constructor.call(this, "textarea", oConfigs);
};
// TextareaCellEditor extends BaseCellEditor
lang.extend(widget.TextareaCellEditor, BCE, {
/////////////////////////////////////////////////////////////////////////////
//
// TextareaCellEditor public properties
//
/////////////////////////////////////////////////////////////////////////////
/**
* Reference to textarea element.
*
* @property textarea
* @type HTMLElement
*/
textarea : null,
/////////////////////////////////////////////////////////////////////////////
//
// TextareaCellEditor public methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* Render a form with textarea.
*
* @method renderForm
*/
renderForm : function() {
var elTextarea = this.getContainerEl().appendChild(document.createElement("textarea"));
this.textarea = elTextarea;
if(this.disableBtns) {
this.handleDisabledBtns();
}
},
/**
* After rendering form, if disabledBtns is set to true, then sets up a mechanism
* to save input without them.
*
* @method handleDisabledBtns
*/
handleDisabledBtns : function() {
Ev.addListener(this.textarea, "blur", function(v){
// Save on blur
this.save();
}, this, true);
},
/**
* Moves TextareaCellEditor UI to a cell.
*
* @method move
*/
move : function() {
this.textarea.style.width = this.getTdEl().offsetWidth + "px";
this.textarea.style.height = "3em";
YAHOO.widget.TextareaCellEditor.superclass.move.call(this);
},
/**
* Resets TextareaCellEditor UI to initial state.
*
* @method resetForm
*/
resetForm : function() {
this.textarea.value = this.value;
},
/**
* Sets focus in TextareaCellEditor.
*
* @method focus
*/
focus : function() {
this.textarea.focus();
this.textarea.select();
},
/**
* Retrieves input value from TextareaCellEditor.
*
* @method getInputValue
*/
getInputValue : function() {
return this.textarea.value;
}
});
// Copy static members to TextareaCellEditor class
lang.augmentObject(widget.TextareaCellEditor, BCE);
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* The TextboxCellEditor class provides functionality for inline editing
* DataTable cell data with an INPUT TYPE=TEXT element.
*
* @namespace YAHOO.widget
* @class TextboxCellEditor
* @extends YAHOO.widget.BaseCellEditor
* @constructor
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.TextboxCellEditor = function(oConfigs) {
this._sId = "yui-textboxceditor" + YAHOO.widget.BaseCellEditor._nCount++;
widget.TextboxCellEditor.superclass.constructor.call(this, "textbox", oConfigs);
};
// TextboxCellEditor extends BaseCellEditor
lang.extend(widget.TextboxCellEditor, BCE, {
/////////////////////////////////////////////////////////////////////////////
//
// TextboxCellEditor public properties
//
/////////////////////////////////////////////////////////////////////////////
/**
* Reference to the textbox element.
*
* @property textbox
*/
textbox : null,
/////////////////////////////////////////////////////////////////////////////
//
// TextboxCellEditor public methods
//
/////////////////////////////////////////////////////////////////////////////
/**
* Render a form with input type=text.
*
* @method renderForm
*/
renderForm : function() {
var elTextbox;
// Bug 1802582: SF3/Mac needs a form element wrapping the input
if(ua.webkit>420) {
elTextbox = this.getContainerEl().appendChild(document.createElement("form")).appendChild(document.createElement("input"));
}
else {
elTextbox = this.getContainerEl().appendChild(document.createElement("input"));
}
elTextbox.type = "text";
this.textbox = elTextbox;
// Save on enter by default
// Bug: 1802582 Set up a listener on each textbox to track on keypress
// since SF/OP can't preventDefault on keydown
Ev.addListener(elTextbox, "keypress", function(v){
if((v.keyCode === 13)) {
// Prevent form submit
YAHOO.util.Event.preventDefault(v);
this.save();
}
}, this, true);
if(this.disableBtns) {
// By default this is no-op since enter saves by default
this.handleDisabledBtns();
}
},
/**
* Moves TextboxCellEditor UI to a cell.
*
* @method move
*/
move : function() {
this.textbox.style.width = this.getTdEl().offsetWidth + "px";
widget.TextboxCellEditor.superclass.move.call(this);
},
/**
* Resets TextboxCellEditor UI to initial state.
*
* @method resetForm
*/
resetForm : function() {
this.textbox.value = lang.isValue(this.value) ? this.value.toString() : "";
},
/**
* Sets focus in TextboxCellEditor.
*
* @method focus
*/
focus : function() {
this.textbox.focus();
this.textbox.select();
},
/**
* Returns new value for TextboxCellEditor.
*
* @method getInputValue
*/
getInputValue : function() {
return this.textbox.value;
}
});
// Copy static members to TextboxCellEditor class
lang.augmentObject(widget.TextboxCellEditor, BCE);
/////////////////////////////////////////////////////////////////////////////
//
// DataTable extension
//
/////////////////////////////////////////////////////////////////////////////
/**
* CellEditor subclasses.
* @property DataTable.Editors
* @type Object
* @static
*/
DT.Editors = {
checkbox : widget.CheckboxCellEditor,
"date" : widget.DateCellEditor,
dropdown : widget.DropdownCellEditor,
radio : widget.RadioCellEditor,
textarea : widget.TextareaCellEditor,
textbox : widget.TextboxCellEditor
};
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* Factory class for instantiating a BaseCellEditor subclass.
*
* @namespace YAHOO.widget
* @class CellEditor
* @extends YAHOO.widget.BaseCellEditor
* @constructor
* @param sType {String} Type indicator, to map to YAHOO.widget.DataTable.Editors.
* @param oConfigs {Object} (Optional) Object literal of configs.
*/
widget.CellEditor = function(sType, oConfigs) {
// Point to one of the subclasses
if(sType && DT.Editors[sType]) {
lang.augmentObject(BCE, DT.Editors[sType]);
return new DT.Editors[sType](oConfigs);
}
else {
return new BCE(null, oConfigs);
}
};
var CE = widget.CellEditor;
// Copy static members to CellEditor class
lang.augmentObject(CE, BCE);
})();