/**
* The DataTable widget provides a progressively enhanced DHTML control for
* displaying tabular data across A-grade browsers.
*
* @module datatable
* @requires yahoo, dom, event, element, datasource
* @optional connection, dragdrop
* @title DataTable Widget
* @beta
*/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/**
* DataTable class for the YUI DataTable widget.
*
* @namespace YAHOO.widget
* @class DataTable
* @uses YAHOO.util.EventProvider
* @constructor
* @param elContainer {HTMLElement} Container element for the TABLE.
* @param aColumnDefs {Object[]} Array of object literal Column definitions.
* @param oDataSource {YAHOO.util.DataSource} DataSource instance.
* @param oConfigs {object} (optional) Object literal of configuration values.
*/
YAHOO.widget.DataTable = function(elContainer,aColumnDefs,oDataSource,oConfigs) {
var DT = YAHOO.widget.DataTable,
DS = YAHOO.util.DataSource;
// Internal vars
this._nIndex = DT._nCount;
this._sId = "yui-dt"+this._nIndex;
this._oChainRender = new YAHOO.util.Chain();
this._oChainSync = new YAHOO.util.Chain();
this._oChainRender.subscribe("end",this._sync, this, true);
// Initialize configs
this._initConfigs(oConfigs);
// Initialize DataSource
this._initDataSource(oDataSource);
if(!this._oDataSource) {
YAHOO.log("Could not instantiate DataTable due to an invalid DataSource", "error", this.toString());
return;
}
// Initialize ColumnSet
this._initColumnSet(aColumnDefs);
if(!this._oColumnSet) {
YAHOO.log("Could not instantiate DataTable due to an invalid ColumnSet", "error", this.toString());
return;
}
// Initialize RecordSet
this._initRecordSet();
if(!this._oRecordSet) {
YAHOO.log("Could not instantiate DataTable due to an invalid RecordSet", "error", this.toString());
return;
}
// Initialize node templates
this._initNodeTemplates();
// Initialize container element
this._initContainerEl(elContainer);
if(!this._elContainer) {
YAHOO.log("Could not instantiate DataTable due to an invalid container element", "error", this.toString());
return;
}
// Initialize the rest of the DOM elements
this._initTableEl();
if(!this._elContainer || !this._elThead || !this._elTbody) {
YAHOO.log("Could not instantiate DataTable due to an invalid DOM elements", "error", this.toString());
return;
}
// Call Element's constructor after DOM elements are created
// but *before* table is populated with data
DT.superclass.constructor.call(this, this._elContainer, this._oConfigs);
// HACK: Set sortedBy values for backward compatibility
var oSortedBy = this.get("sortedBy");
if(oSortedBy) {
if(oSortedBy.dir == "desc") {
this._configs.sortedBy.value.dir = DT.CLASS_DESC;
}
else if(oSortedBy.dir == "asc") {
this._configs.sortedBy.value.dir = DT.CLASS_ASC;
}
}
//HACK: Set the paginator values. Attribute doesn't afford for merging
// obj value's keys. It's all or nothing. Merge in provided keys.
if(this._oConfigs.paginator && !(this._oConfigs.paginator instanceof YAHOO.widget.Paginator)) {
// Backward compatibility
this.updatePaginator(this._oConfigs.paginator);
}
// Initialize inline Cell editing
this._initCellEditorEl();
// Initialize Column sort
this._initColumnSort();
// Once per instance
YAHOO.util.Event.addListener(document, "click", this._onDocumentClick, this);
DT._nCount++;
DT._nCurrentCount++;
// Send a simple initial request
var oCallback = {
success : this.onDataReturnSetRows,
failure : this.onDataReturnSetRows,
scope : this,
argument: {}
};
if(this.get("initialLoad") === true) {
this._oDataSource.sendRequest(this.get("initialRequest"), oCallback);
}
// Do not send an initial request at all
else if(this.get("initialLoad") === false) {
this.showTableMessage(DT.MSG_EMPTY, DT.CLASS_EMPTY);
this._oChainRender.add({
method: function() {
if((this instanceof DT) && this._sId && this._bInit) {
this._bInit = false;
this.fireEvent("initEvent");
YAHOO.log("DataTable initialized with no rows", "info", this.toString());
}
},
scope: this
});
this._oChainRender.run();
}
// Send an initial request with a custom payload
else {
var oCustom = this.get("initialLoad");
oCallback.argument = oCustom.argument;
this._oDataSource.sendRequest(oCustom.request, oCallback);
}
};
/////////////////////////////////////////////////////////////////////////////
//
// Public constants
//
/////////////////////////////////////////////////////////////////////////////
(function () {
var lang = YAHOO.lang,
util = YAHOO.util,
widget = YAHOO.widget,
ua = YAHOO.env.ua,
Dom = util.Dom,
Ev = util.Event,
DS = util.DataSource,
DT = widget.DataTable,
Pag = widget.Paginator;
lang.augmentObject(DT, {
/**
* Class name assigned to liner DIV elements.
*
* @property DataTable.CLASS_LINER
* @type String
* @static
* @final
* @default "yui-dt-liner"
*/
CLASS_LINER : "yui-dt-liner",
/**
* Class name assigned to display label elements.
*
* @property DataTable.CLASS_LABEL
* @type String
* @static
* @final
* @default "yui-dt-label"
*/
CLASS_LABEL : "yui-dt-label",
/**
* Class name assigned to Column drag target.
*
* @property DataTable.CLASS_COLTARGET
* @type String
* @static
* @final
* @default "yui-dt-coltarget"
*/
CLASS_COLTARGET : "yui-dt-coltarget",
/**
* Class name assigned to resizer handle elements.
*
* @property DataTable.CLASS_RESIZER
* @type String
* @static
* @final
* @default "yui-dt-resizer"
*/
CLASS_RESIZER : "yui-dt-resizer",
/**
* Class name assigned to resizer proxy elements.
*
* @property DataTable.CLASS_RESIZERPROXY
* @type String
* @static
* @final
* @default "yui-dt-resizerproxy"
*/
CLASS_RESIZERPROXY : "yui-dt-resizerproxy",
/**
* Class name assigned to Editor container elements.
*
* @property DataTable.CLASS_EDITOR
* @type String
* @static
* @final
* @default "yui-dt-editor"
*/
CLASS_EDITOR : "yui-dt-editor",
/**
* Class name assigned to paginator container elements.
*
* @property DataTable.CLASS_PAGINATOR
* @type String
* @static
* @final
* @default "yui-dt-paginator"
*/
CLASS_PAGINATOR : "yui-dt-paginator",
/**
* Class name assigned to page number indicators.
*
* @property DataTable.CLASS_PAGE
* @type String
* @static
* @final
* @default "yui-dt-page"
*/
CLASS_PAGE : "yui-dt-page",
/**
* Class name assigned to default indicators.
*
* @property DataTable.CLASS_DEFAULT
* @type String
* @static
* @final
* @default "yui-dt-default"
*/
CLASS_DEFAULT : "yui-dt-default",
/**
* Class name assigned to previous indicators.
*
* @property DataTable.CLASS_PREVIOUS
* @type String
* @static
* @final
* @default "yui-dt-previous"
*/
CLASS_PREVIOUS : "yui-dt-previous",
/**
* Class name assigned next indicators.
*
* @property DataTable.CLASS_NEXT
* @type String
* @static
* @final
* @default "yui-dt-next"
*/
CLASS_NEXT : "yui-dt-next",
/**
* Class name assigned to first elements.
*
* @property DataTable.CLASS_FIRST
* @type String
* @static
* @final
* @default "yui-dt-first"
*/
CLASS_FIRST : "yui-dt-first",
/**
* Class name assigned to last elements.
*
* @property DataTable.CLASS_LAST
* @type String
* @static
* @final
* @default "yui-dt-last"
*/
CLASS_LAST : "yui-dt-last",
/**
* Class name assigned to even elements.
*
* @property DataTable.CLASS_EVEN
* @type String
* @static
* @final
* @default "yui-dt-even"
*/
CLASS_EVEN : "yui-dt-even",
/**
* Class name assigned to odd elements.
*
* @property DataTable.CLASS_ODD
* @type String
* @static
* @final
* @default "yui-dt-odd"
*/
CLASS_ODD : "yui-dt-odd",
/**
* Class name assigned to selected elements.
*
* @property DataTable.CLASS_SELECTED
* @type String
* @static
* @final
* @default "yui-dt-selected"
*/
CLASS_SELECTED : "yui-dt-selected",
/**
* Class name assigned to highlighted elements.
*
* @property DataTable.CLASS_HIGHLIGHTED
* @type String
* @static
* @final
* @default "yui-dt-highlighted"
*/
CLASS_HIGHLIGHTED : "yui-dt-highlighted",
/**
* Class name assigned to hidden elements.
*
* @property DataTable.CLASS_HIDDEN
* @type String
* @static
* @final
* @default "yui-dt-hidden"
*/
CLASS_HIDDEN : "yui-dt-hidden",
/**
* Class name assigned to disabled elements.
*
* @property DataTable.CLASS_DISABLED
* @type String
* @static
* @final
* @default "yui-dt-disabled"
*/
CLASS_DISABLED : "yui-dt-disabled",
/**
* Class name assigned to message containers.
*
* @property DataTable.CLASS_MSG
* @type String
* @static
* @final
* @default "yui-dt-msg"
*/
CLASS_MSG : "yui-dt-msg",
/**
* Class name assigned to empty indicators.
*
* @property DataTable.CLASS_EMPTY
* @type String
* @static
* @final
* @default "yui-dt-empty"
*/
CLASS_EMPTY : "yui-dt-empty",
/**
* Class name assigned to loading indicatorx.
*
* @property DataTable.CLASS_LOADING
* @type String
* @static
* @final
* @default "yui-dt-loading"
*/
CLASS_LOADING : "yui-dt-loading",
/**
* Class name assigned to error indicators.
*
* @property DataTable.CLASS_ERROR
* @type String
* @static
* @final
* @default "yui-dt-error"
*/
CLASS_ERROR : "yui-dt-error",
/**
* Class name assigned to editable elements.
*
* @property DataTable.CLASS_EDITABLE
* @type String
* @static
* @final
* @default "yui-dt-editable"
*/
CLASS_EDITABLE : "yui-dt-editable",
/**
* Class name assigned to draggable elements.
*
* @property DataTable.CLASS_DRAGGABLE
* @type String
* @static
* @final
* @default "yui-dt-draggable"
*/
CLASS_DRAGGABLE : "yui-dt-draggable",
/**
* Class name assigned to resizeable elements.
*
* @property DataTable.CLASS_RESIZEABLE
* @type String
* @static
* @final
* @default "yui-dt-resizeable"
*/
CLASS_RESIZEABLE : "yui-dt-resizeable",
/**
* Class name assigned to scrollable elements.
*
* @property DataTable.CLASS_SCROLLABLE
* @type String
* @static
* @final
* @default "yui-dt-scrollable"
*/
CLASS_SCROLLABLE : "yui-dt-scrollable",
/**
* Color assigned to header filler on scrollable tables when columnFiller
* is set to true.
*
* @property DataTable.CLASS_COLUMN_FILLER_COLOR
* @type String
* @static
* @final
* @default "#F2F2F2"
*/
COLOR_COLUMNFILLER : "#F2F2F2",
/**
* Class name assigned to sortable elements.
*
* @property DataTable.CLASS_SORTABLE
* @type String
* @static
* @final
* @default "yui-dt-sortable"
*/
CLASS_SORTABLE : "yui-dt-sortable",
/**
* Class name assigned to ascending elements.
*
* @property DataTable.CLASS_ASC
* @type String
* @static
* @final
* @default "yui-dt-asc"
*/
CLASS_ASC : "yui-dt-asc",
/**
* Class name assigned to descending elements.
*
* @property DataTable.CLASS_DESC
* @type String
* @static
* @final
* @default "yui-dt-desc"
*/
CLASS_DESC : "yui-dt-desc",
/**
* Class name assigned to BUTTON elements and/or container elements.
*
* @property DataTable.CLASS_BUTTON
* @type String
* @static
* @final
* @default "yui-dt-button"
*/
CLASS_BUTTON : "yui-dt-button",
/**
* Class name assigned to INPUT TYPE=CHECKBOX elements and/or container elements.
*
* @property DataTable.CLASS_CHECKBOX
* @type String
* @static
* @final
* @default "yui-dt-checkbox"
*/
CLASS_CHECKBOX : "yui-dt-checkbox",
/**
* Class name assigned to SELECT elements and/or container elements.
*
* @property DataTable.CLASS_DROPDOWN
* @type String
* @static
* @final
* @default "yui-dt-dropdown"
*/
CLASS_DROPDOWN : "yui-dt-dropdown",
/**
* Class name assigned to INPUT TYPE=RADIO elements and/or container elements.
*
* @property DataTable.CLASS_RADIO
* @type String
* @static
* @final
* @default "yui-dt-radio"
*/
CLASS_RADIO : "yui-dt-radio",
/**
* Message to display if DataTable has no data.
*
* @property DataTable.MSG_EMPTY
* @type String
* @static
* @final
* @default "No records found."
*/
MSG_EMPTY : "No records found.",
/**
* Message to display while DataTable is loading data.
*
* @property DataTable.MSG_LOADING
* @type String
* @static
* @final
* @default "Loading data..."
*/
MSG_LOADING : "Loading data...",
/**
* Message to display while DataTable has data error.
*
* @property DataTable.MSG_ERROR
* @type String
* @static
* @final
* @default "Data error."
*/
MSG_ERROR : "Data error.",
/////////////////////////////////////////////////////////////////////////
//
// Private static variables
//
/////////////////////////////////////////////////////////////////////////
/**
* Internal class variable for indexing multiple DataTable instances.
*
* @property DataTable._nCount
* @type Number
* @private
* @static
*/
_nCount : 0,
/**
* Internal class variable tracking current number of DataTable instances,
* so that certain class values can be reset when all instances are destroyed.
*
* @property DataTable._nCurrentCount
* @type Number
* @private
* @static
*/
_nCurrentCount : 0,
/**
* Reference to STYLE node that is dynamically created and written to
* in order to manage Column widths.
*
* @property DataTable._elStylesheet
* @type HTMLElement
* @private
* @static
*/
_elStylesheet : null,
/**
* Set to true if _elStylesheet cannot be populated due to browser incompatibility.
*
* @property DataTable._bStylesheetFallback
* @type boolean
* @private
* @static
*/
_bStylesheetFallback : (ua.ie && (ua.ie<7)) ? true : false,
/**
* Object literal hash of Columns and their dynamically create style rules.
*
* @property DataTable._oStylesheetRules
* @type Object
* @private
* @static
*/
_oStylesheetRules : {},
/**
* Element reference to shared Column drag target.
*
* @property DataTable._elColumnDragTarget
* @type HTMLElement
* @private
* @static
*/
_elColumnDragTarget : null,
/**
* Element reference to shared Column resizer proxy.
*
* @property DataTable._elColumnResizerProxy
* @type HTMLElement
* @private
* @static
*/
_elColumnResizerProxy : null,
/**
* Clones object literal or array of object literals.
*
* @method DataTable._cloneObject
* @param o {Object} Object.
* @private
* @static
*/
_cloneObject : function(o) {
if(!lang.isValue(o)) {
return o;
}
var copy = {};
if(lang.isArray(o)) {
var array = [];
for(var i=0,len=o.length;i<len;i++) {
array[i] = DT._cloneObject(o[i]);
}
copy = array;
}
else if(o.constructor && (o.constructor == Object)) {
for (var x in o){
if(lang.hasOwnProperty(o, x)) {
if(lang.isValue(o[x]) && (o[x].constructor == Object) || lang.isArray(o[x])) {
copy[x] = DT._cloneObject(o[x]);
}
else {
copy[x] = o[x];
}
}
}
}
else {
copy = o;
}
return copy;
},
/**
* Creates HTML markup for shared Column drag target.
*
* @method DataTable._initColumnDragTargetEl
* @return {HTMLElement} Reference to Column drag target.
* @private
* @static
*/
_initColumnDragTargetEl : function() {
if(!DT._elColumnDragTarget) {
// Attach Column drag target element as first child of body
var elColumnDragTarget = document.createElement('div');
elColumnDragTarget.id = "yui-dt-coltarget";
elColumnDragTarget.className = DT.CLASS_COLTARGET;
elColumnDragTarget.style.display = "none";
document.body.insertBefore(elColumnDragTarget, document.body.firstChild);
// Internal tracker of Column drag target
DT._elColumnDragTarget = elColumnDragTarget;
}
return DT._elColumnDragTarget;
},
/**
* Creates HTML markup for shared Column resizer proxy.
*
* @method DataTable._initColumnResizerProxyEl
* @return {HTMLElement} Reference to Column resizer proxy.
* @private
* @static
*/
_initColumnResizerProxyEl : function() {
if(!DT._elColumnResizerProxy) {
// Attach Column resizer element as first child of body
var elColumnResizerProxy = document.createElement("div");
elColumnResizerProxy.id = "yui-dt-colresizerproxy";
Dom.addClass(elColumnResizerProxy, DT.CLASS_RESIZERPROXY);
document.body.insertBefore(elColumnResizerProxy, document.body.firstChild);
// Internal tracker of Column resizer proxy
DT._elColumnResizerProxy = elColumnResizerProxy;
}
return DT._elColumnResizerProxy;
},
/**
* Outputs markup into the given TH based on given Column.
*
* @method DataTable.formatTheadCell
* @param elCellLabel {HTMLElement} The label DIV element within the TH liner.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oSelf {DataTable} DataTable instance.
* @static
*/
formatTheadCell : function(elCellLabel, oColumn, oSelf) {
var sKey = oColumn.getKey();
var sLabel = lang.isValue(oColumn.label) ? oColumn.label : sKey;
// Add accessibility link for sortable Columns
if(oColumn.sortable) {
// Calculate the direction
var sSortClass = oSelf.getColumnSortDir(oColumn);
var sSortDir = (sSortClass === DT.CLASS_DESC) ? "descending" : "ascending";
// Generate a unique HREF for visited status
var sHref = oSelf.getId() + "-sort" + oColumn.getId() + "-" + sSortDir;
// Generate a dynamic TITLE for sort status
var sTitle = "Click to sort " + sSortDir;
// Format the element
elCellLabel.innerHTML = "<a href=\"" + sHref + "\" title=\"" + sTitle + "\" class=\"" + DT.CLASS_SORTABLE + "\">" + sLabel + "</a>";
}
// Just display the label for non-sortable Columns
else {
elCellLabel.innerHTML = sLabel;
}
},
/**
* Formats a BUTTON element.
*
* @method DataTable.formatButton
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object | Boolean} Data value for the cell. By default, the value
* is what gets written to the BUTTON.
* @static
*/
formatButton : function(el, oRecord, oColumn, oData) {
var sValue = lang.isValue(oData) ? oData : "Click";
//TODO: support YAHOO.widget.Button
//if(YAHOO.widget.Button) {
//}
//else {
el.innerHTML = "<button type=\"button\" class=\""+
DT.CLASS_BUTTON + "\">" + sValue + "</button>";
//}
},
/**
* Formats a CHECKBOX element.
*
* @method DataTable.formatCheckbox
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object | Boolean} Data value for the cell. Can be a simple
* Boolean to indicate whether checkbox is checked or not. Can be object literal
* {checked:bBoolean, label:sLabel}. Other forms of oData require a custom
* formatter.
* @static
*/
formatCheckbox : function(el, oRecord, oColumn, oData) {
var bChecked = oData;
bChecked = (bChecked) ? " checked" : "";
el.innerHTML = "<input type=\"checkbox\"" + bChecked +
" class=\"" + DT.CLASS_CHECKBOX + "\">";
},
/**
* Formats currency. Default unit is USD.
*
* @method DataTable.formatCurrency
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Number} Data value for the cell.
* @static
*/
formatCurrency : function(el, oRecord, oColumn, oData) {
el.innerHTML = util.Number.format(oData, {
prefix:"$",
decimalPlaces:2,
decimalSeparator:".",
thousandsSeparator:","
});
},
/**
* Formats JavaScript Dates.
*
* @method DataTable.formatDate
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} Data value for the cell, or null.
* @static
*/
formatDate : function(el, oRecord, oColumn, oData) {
el.innerHTML = util.Date.format(oData, {format:"MM/DD/YYYY"});
},
/**
* Formats SELECT elements.
*
* @method DataTable.formatDropdown
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} Data value for the cell, or null.
* @static
*/
formatDropdown : function(el, oRecord, oColumn, oData) {
var selectedValue = (lang.isValue(oData)) ? oData : oRecord.getData(oColumn.key);
var options = (lang.isArray(oColumn.dropdownOptions)) ?
oColumn.dropdownOptions : null;
var selectEl;
var collection = el.getElementsByTagName("select");
// Create the form element only once, so we can attach the onChange listener
if(collection.length === 0) {
// Create SELECT element
selectEl = document.createElement("select");
Dom.addClass(selectEl, DT.CLASS_DROPDOWN);
selectEl = el.appendChild(selectEl);
// Add event listener
Ev.addListener(selectEl,"change",this._onDropdownChange,this);
}
selectEl = collection[0];
// Update the form element
if(selectEl) {
// Clear out previous options
selectEl.innerHTML = "";
// We have options to populate
if(options) {
// Create OPTION elements
for(var i=0; i<options.length; i++) {
var option = options[i];
var optionEl = document.createElement("option");
optionEl.value = (lang.isValue(option.value)) ?
option.value : option;
optionEl.innerHTML = (lang.isValue(option.text)) ?
option.text : option;
optionEl = selectEl.appendChild(optionEl);
if (optionEl.value == selectedValue) {
optionEl.selected = true;
}
}
}
// Selected value is our only option
else {
selectEl.innerHTML = "<option selected value=\"" + selectedValue + "\">" + selectedValue + "</option>";
}
}
else {
el.innerHTML = lang.isValue(oData) ? oData : "";
}
},
/**
* Formats emails.
*
* @method DataTable.formatEmail
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} Data value for the cell, or null.
* @static
*/
formatEmail : function(el, oRecord, oColumn, oData) {
if(lang.isString(oData)) {
el.innerHTML = "<a href=\"mailto:" + oData + "\">" + oData + "</a>";
}
else {
el.innerHTML = lang.isValue(oData) ? oData : "";
}
},
/**
* Formats links.
*
* @method DataTable.formatLink
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} Data value for the cell, or null.
* @static
*/
formatLink : function(el, oRecord, oColumn, oData) {
if(lang.isString(oData)) {
el.innerHTML = "<a href=\"" + oData + "\">" + oData + "</a>";
}
else {
el.innerHTML = lang.isValue(oData) ? oData : "";
}
},
/**
* Formats numbers.
*
* @method DataTable.formatNumber
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} Data value for the cell, or null.
* @static
*/
formatNumber : function(el, oRecord, oColumn, oData) {
if(lang.isNumber(oData)) {
el.innerHTML = oData;
}
else {
el.innerHTML = lang.isValue(oData) ? oData : "";
}
},
/**
* Formats INPUT TYPE=RADIO elements.
*
* @method DataTable.formatRadio
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} (Optional) Data value for the cell.
* @static
*/
formatRadio : function(el, oRecord, oColumn, oData) {
var bChecked = oData;
bChecked = (bChecked) ? " checked" : "";
el.innerHTML = "<input type=\"radio\"" + bChecked +
" name=\"col" + oColumn.getId() + "-radio\"" +
" class=\"" + DT.CLASS_RADIO+ "\">";
},
/**
* Formats text strings.
*
* @method DataTable.formatText
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} (Optional) Data value for the cell.
* @static
*/
formatText : function(el, oRecord, oColumn, oData) {
var value = (lang.isValue(oRecord.getData(oColumn.key))) ?
oRecord.getData(oColumn.key) : "";
//TODO: move to util function
el.innerHTML = value.toString().replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
},
/**
* Formats TEXTAREA elements.
*
* @method DataTable.formatTextarea
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} (Optional) Data value for the cell.
* @static
*/
formatTextarea : function(el, oRecord, oColumn, oData) {
var value = (lang.isValue(oRecord.getData(oColumn.key))) ?
oRecord.getData(oColumn.key) : "";
var markup = "<textarea>" + value + "</textarea>";
el.innerHTML = markup;
},
/**
* Formats INPUT TYPE=TEXT elements.
*
* @method DataTable.formatTextbox
* @param el {HTMLElement} The element to format with markup.
* @param oRecord {YAHOO.widget.Record} Record instance.
* @param oColumn {YAHOO.widget.Column} Column instance.
* @param oData {Object} (Optional) Data value for the cell.
* @static
*/
formatTextbox : function(el, oRecord, oColumn, oData) {
var value = (lang.isValue(oRecord.getData(oColumn.key))) ?
oRecord.getData(oColumn.key) : "";
var markup = "<input type=\"text\" value=\"" + value + "\">";
el.innerHTML = markup;
},
/**
* Handles Paginator changeRequest events for static DataSources
* (i.e. DataSources that return all data immediately)
* @method DataTable.handleSimplePagination
* @param {object} the requested state of the pagination
* @param {DataTable} the DataTable instance
* @static
*/
handleSimplePagination : function (oState,self) {
// Set the core pagination values silently (the second param)
// to avoid looping back through the changeRequest mechanism
oState.paginator.setTotalRecords(oState.totalRecords,true);
oState.paginator.setStartIndex(oState.recordOffset,true);
oState.paginator.setRowsPerPage(oState.rowsPerPage,true);
self.render();
},
/**
* Handles Paginator changeRequest events for dynamic DataSources
* such as DataSource.TYPE_XHR or DataSource.TYPE_JSFUNCTION.
* @method DataTable.handleDataSourcePagination
* @param {object} the requested state of the pagination
* @param {DataTable} the DataTable instance
* @static
*/
handleDataSourcePagination : function (oState,self) {
var requestedRecords = oState.records[1] - oState.recordOffset;
// Translate the proposed page state into a DataSource request param
var generateRequest = self.get('generateRequest');
var request = generateRequest({ pagination : oState }, self);
var callback = {
success : self.onDataReturnSetRows,
failure : self.onDataReturnSetRows,
argument : {
startIndex : oState.recordOffset,
pagination : oState
},
scope : self
};
self._oDataSource.sendRequest(request, callback);
},
/**
* Enables CHECKBOX Editor.
*
* @method DataTable.editCheckbox
* @param oEditor {Object} Object literal representation of Editor values.
* @param oSelf {DataTable} Reference back to DataTable instance.
* @static
*/
//DT.editCheckbox = function(elContainer, oRecord, oColumn, oEditor, oSelf)
editCheckbox : function(oEditor, oSelf) {
var elCell = oEditor.cell;
var oRecord = oEditor.record;
var oColumn = oEditor.column;
var elContainer = oEditor.container;
var aCheckedValues = oEditor.value;
if(!lang.isArray(aCheckedValues)) {
aCheckedValues = [aCheckedValues];
}
// Checkboxes
if(oColumn.editorOptions && lang.isArray(oColumn.editorOptions.checkboxOptions)) {
var checkboxOptions = oColumn.editorOptions.checkboxOptions;
var checkboxValue, checkboxId, elLabel, j, k;
// First create the checkbox buttons in an IE-friendly way
for(j=0; j<checkboxOptions.length; j++) {
checkboxValue = lang.isValue(checkboxOptions[j].label) ?
checkboxOptions[j].label : checkboxOptions[j];
checkboxId = oSelf.getId() + "-editor-checkbox" + j;
elContainer.innerHTML += "<input type=\"checkbox\"" +
" name=\"" + oSelf.getId() + "-editor-checkbox\"" +
" value=\"" + checkboxValue + "\"" +
" id=\"" + checkboxId + "\">";
// Then create the labels in an IE-friendly way
elLabel = elContainer.appendChild(document.createElement("label"));
elLabel.htmlFor = checkboxId;
elLabel.innerHTML = checkboxValue;
}
var aCheckboxEls = [];
var checkboxEl;
// Loop through checkboxes to check them
for(j=0; j<checkboxOptions.length; j++) {
checkboxEl = Dom.get(oSelf.getId() + "-editor-checkbox" + j);
aCheckboxEls.push(checkboxEl);
for(k=0; k<aCheckedValues.length; k++) {
if(checkboxEl.value === aCheckedValues[k]) {
checkboxEl.checked = true;
}
}
// Focus the first checkbox
if(j===0) {
oSelf._focusEl(checkboxEl);
}
}
// Loop through checkboxes to assign click handlers
for(j=0; j<checkboxOptions.length; j++) {
checkboxEl = Dom.get(oSelf.getId() + "-editor-checkbox" + j);
Ev.addListener(checkboxEl, "click", function(){
var aNewValues = [];
for(var m=0; m<aCheckboxEls.length; m++) {
if(aCheckboxEls[m].checked) {
aNewValues.push(aCheckboxEls[m].value);
}
}
oSelf._oCellEditor.value = aNewValues;
oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
});
}
}
},
/**
* Enables Date Editor.
*
* @method DataTable.editDate
* @param oEditor {Object} Object literal representation of Editor values.
* @param oSelf {DataTable} Reference back to DataTable instance.
* @static
*/
editDate : function(oEditor, oSelf) {
var elCell = oEditor.cell;
var oRecord = oEditor.record;
var oColumn = oEditor.column;
var elContainer = oEditor.container;
var value = oEditor.value;
// Set a default
if(!(value instanceof Date)) {
value = oEditor.defaultValue || new Date();
}
// Calendar widget
if(YAHOO.widget.Calendar) {
var selectedValue = (value.getMonth()+1)+"/"+value.getDate()+"/"+value.getFullYear();
var calContainer = elContainer.appendChild(document.createElement("div"));
var calPrefix = oColumn.getColEl();
calContainer.id = calPrefix + "-dateContainer";
var calendar =
new YAHOO.widget.Calendar(calPrefix + "-date",
calContainer.id,
{selected:selectedValue, pagedate:value});
calendar.render();
calContainer.style.cssFloat = "none";
if(ua.ie) {
var calFloatClearer = elContainer.appendChild(document.createElement("br"));
calFloatClearer.style.clear = "both";
}
calendar.selectEvent.subscribe(function(type, args, obj) {
oSelf._oCellEditor.value = new Date(args[0][0][0], args[0][0][1]-1, args[0][0][2]);
oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
});
}
else {
//TODO;
}
},
/**
* Enables SELECT Editor.
*
* @method DataTable.editDropdown
* @param oEditor {Object} Object literal representation of Editor values.
* @param oSelf {DataTable} Reference back to DataTable instance.
* @static
*/
editDropdown : function(oEditor, oSelf) {
var elCell = oEditor.cell;
var oRecord = oEditor.record;
var oColumn = oEditor.column;
var elContainer = oEditor.container;
var value = oEditor.value;
// Set a default
if(!lang.isValue(value)) {
value = oEditor.defaultValue;
}
// Textbox
var elDropdown = elContainer.appendChild(document.createElement("select"));
var dropdownOptions = (oColumn.editorOptions && lang.isArray(oColumn.editorOptions.dropdownOptions)) ?
oColumn.editorOptions.dropdownOptions : [];
for(var j=0; j<dropdownOptions.length; j++) {
var dropdownOption = dropdownOptions[j];
var elOption = document.createElement("option");
elOption.value = (lang.isValue(dropdownOption.value)) ?
dropdownOption.value : dropdownOption;
elOption.innerHTML = (lang.isValue(dropdownOption.text)) ?
dropdownOption.text : dropdownOption;
elOption =