2 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 * The DataTable widget provides a progressively enhanced DHTML control for
9 * displaying tabular data across A-grade browsers.
12 * @requires yahoo, dom, event, datasource
14 * @title DataTable Widget
18 /****************************************************************************/
19 /****************************************************************************/
20 /****************************************************************************/
23 * DataTable class for the YUI DataTable widget.
25 * @namespace YAHOO.widget
27 * @uses YAHOO.util.EventProvider
29 * @param elContainer {HTMLElement} Container element for the TABLE.
30 * @param aColumnDefs {Object[]} Array of object literal Column definitions.
31 * @param oDataSource {YAHOO.util.DataSource} DataSource instance.
32 * @param oConfigs {object} (optional) Object literal of configuration values.
34 YAHOO.widget.DataTable = function(elContainer,aColumnDefs,oDataSource,oConfigs) {
36 this._nIndex = YAHOO.widget.DataTable._nCount;
37 this._sName = "instance" + this._nIndex;
38 this.id = "yui-dt"+this._nIndex;
40 // Initialize container element
41 this._initContainerEl(elContainer);
42 if(!this._elContainer) {
43 YAHOO.log("Could not instantiate DataTable due to an invalid container element", "error", this.toString());
48 this._initConfigs(oConfigs);
50 // Initialize ColumnSet
51 this._initColumnSet(aColumnDefs);
52 if(!this._oColumnSet) {
53 YAHOO.log("Could not instantiate DataTable due to an invalid ColumnSet", "error", this.toString());
57 // Initialize RecordSet
58 this._initRecordSet();
59 if(!this._oRecordSet) {
60 YAHOO.log("Could not instantiate DataTable due to an invalid RecordSet", "error", this.toString());
64 // Initialize DataSource
65 this._initDataSource(oDataSource);
66 if(!this._oDataSource) {
67 YAHOO.log("Could not instantiate DataTable due to an invalid DataSource", "error", this.toString());
71 // Progressive enhancement special case
72 if(this._oDataSource.dataType == YAHOO.util.DataSource.TYPE_HTMLTABLE) {
73 this._oDataSource.sendRequest(this.get("initialRequest"), this._onDataReturnEnhanceTable, this);
76 // Initialize DOM elements
78 if(!this._elTable || !this._elThead || !this._elTbody) {
79 YAHOO.log("Could not instantiate DataTable due to an invalid DOM elements", "error", this.toString());
83 // Call Element's constructor after DOM elements are created
84 // but *before* table is populated with data
85 YAHOO.widget.DataTable.superclass.constructor.call(this, this._elContainer, this._oConfigs);
87 //HACK: Set the Paginator values here via updatePaginator
88 if(this._oConfigs && this._oConfigs.paginator) {
89 this.updatePaginator(this._oConfigs.paginator);
92 // Send out for data in an asynchronous request
93 this._oDataSource.sendRequest(this.get("initialRequest"), this.onDataReturnInitializeTable, this);
96 // Initialize inline Cell editing
97 this._initCellEditorEl();
99 // Initialize Column sort
100 this._initColumnSort();
102 // Initialize DOM event listeners
103 this._initDomEvents();
105 YAHOO.widget.DataTable._nCount++;
106 YAHOO.log("DataTable initialized", "info", this.toString());
109 if(YAHOO.util.Element) {
110 YAHOO.lang.extend(YAHOO.widget.DataTable, YAHOO.util.Element);
113 YAHOO.log("Missing dependency: YAHOO.util.Element","error",this.toString());
116 /////////////////////////////////////////////////////////////////////////////
118 // Superclass methods
120 /////////////////////////////////////////////////////////////////////////////
123 * Implementation of Element's abstract method. Sets up config values.
125 * @method initAttributes
126 * @param oConfigs {Object} (Optional) Object literal definition of configuration values.
130 YAHOO.widget.DataTable.prototype.initAttributes = function(oConfigs) {
131 oConfigs = oConfigs || {};
132 YAHOO.widget.DataTable.superclass.initAttributes.call(this, oConfigs);
136 * @description Value for the SUMMARY attribute.
139 this.setAttributeConfig("summary", {
141 validator: YAHOO.lang.isString,
142 method: function(sSummary) {
143 this._elTable.summary = sSummary;
148 * @config selectionMode
149 * @description Specifies row or cell selection mode. Accepts the following strings:
151 * <dt>"standard"</dt>
152 * <dd>Standard row selection with support for modifier keys to enable
153 * multiple selections.</dd>
156 * <dd>Row selection with modifier keys disabled to not allow
157 * multiple selections.</dd>
159 * <dt>"singlecell"</dt>
160 * <dd>Cell selection with modifier keys disabled to not allow
161 * multiple selections.</dd>
163 * <dt>"cellblock"</dt>
164 * <dd>Cell selection with support for modifier keys to enable multiple
165 * selections in a block-fashion, like a spreadsheet.</dd>
167 * <dt>"cellrange"</dt>
168 * <dd>Cell selection with support for modifier keys to enable multiple
169 * selections in a range-fashion, like a calendar.</dd>
172 * @default "standard"
175 this.setAttributeConfig("selectionMode", {
177 validator: YAHOO.lang.isString
181 * @config initialRequest
182 * @description Defines the initial request that gets sent to the DataSource.
185 this.setAttributeConfig("initialRequest", {
187 validator: YAHOO.lang.isString
192 * @description Object literal provides metadata for initial sort values if
193 * data will arrive pre-sorted:
195 * <dt>sortedBy.key</dt>
196 * <dd>Key of sorted Column</dd>
197 * <dt>sortedBy.dir</dt>
198 * <dd>Initial sort direction, either "asc" or "desc"</dd>
202 this.setAttributeConfig("sortedBy", {
204 // TODO: accepted array for nested sorts
205 validator: function(oNewSortedBy) {
206 return (oNewSortedBy && (oNewSortedBy.constructor == Object) && oNewSortedBy.key);
208 method: function(oNewSortedBy) {
209 // Remove ASC/DESC from TH
210 var oOldSortedBy = this.get("sortedBy");
211 if(oOldSortedBy && (oOldSortedBy.constructor == Object) && oOldSortedBy.key) {
212 var oldColumn = this._oColumnSet.getColumn(oOldSortedBy.key);
213 var oldThEl = this.getThEl(oldColumn);
214 YAHOO.util.Dom.removeClass(oldThEl, YAHOO.widget.DataTable.CLASS_ASC);
215 YAHOO.util.Dom.removeClass(oldThEl, YAHOO.widget.DataTable.CLASS_DESC);
218 // Set ASC/DESC on TH
219 var column = (oNewSortedBy.column) ? oNewSortedBy.column : this._oColumnSet.getColumn(oNewSortedBy.key);
221 var newClass = (oNewSortedBy.dir && (oNewSortedBy.dir != "asc")) ?
222 YAHOO.widget.DataTable.CLASS_DESC :
223 YAHOO.widget.DataTable.CLASS_ASC;
224 YAHOO.util.Dom.addClass(this.id + "-col" + column.getId(), newClass);
231 * @description Object literal of pagination values.
233 * { containers:[], // UI container elements <br>
234 * rowsPerPage:500, // 500 rows <br>
235 * currentPage:1, // page one <br>
236 * pageLinks:0, // show all links <br>
237 * pageLinksStart:1, // first link is page 1 <br>
238 * dropdownOptions:null, // no dropdown <br>
239 * links: [], // links elements <br>
240 * dropdowns: [] } //dropdown elements
244 this.setAttributeConfig("paginator", {
246 rowsPerPage:500, // 500 rows per page
247 currentPage:1, // show page one
248 startRecordIndex:0, // start with first Record
249 totalRecords:0, // how many Records total
250 totalPages:0, // how many pages total
251 rowsThisPage:0, // how many rows this page
252 pageLinks:0, // show all links
253 pageLinksStart:1, // first link is page 1
254 dropdownOptions: null, //no dropdown
255 containers:[], // Paginator container element references
256 dropdowns: [], //dropdown element references,
257 links: [] // links elements
259 validator: function(oNewPaginator) {
260 if(oNewPaginator && (oNewPaginator.constructor == Object)) {
261 // Check for incomplete set of values
262 if((oNewPaginator.rowsPerPage !== undefined) &&
263 (oNewPaginator.currentPage !== undefined) &&
264 (oNewPaginator.startRecordIndex !== undefined) &&
265 (oNewPaginator.totalRecords !== undefined) &&
266 (oNewPaginator.totalPages !== undefined) &&
267 (oNewPaginator.rowsThisPage !== undefined) &&
268 (oNewPaginator.pageLinks !== undefined) &&
269 (oNewPaginator.pageLinksStart !== undefined) &&
270 (oNewPaginator.dropdownOptions !== undefined) &&
271 (oNewPaginator.containers !== undefined) &&
272 (oNewPaginator.dropdowns !== undefined) &&
273 (oNewPaginator.links !== undefined)) {
275 // Validate each value
276 if(YAHOO.lang.isNumber(oNewPaginator.rowsPerPage) &&
277 YAHOO.lang.isNumber(oNewPaginator.currentPage) &&
278 YAHOO.lang.isNumber(oNewPaginator.startRecordIndex) &&
279 YAHOO.lang.isNumber(oNewPaginator.totalRecords) &&
280 YAHOO.lang.isNumber(oNewPaginator.totalPages) &&
281 YAHOO.lang.isNumber(oNewPaginator.rowsThisPage) &&
282 YAHOO.lang.isNumber(oNewPaginator.pageLinks) &&
283 YAHOO.lang.isNumber(oNewPaginator.pageLinksStart) &&
284 YAHOO.lang.isArray(oNewPaginator.dropdownOptions) &&
285 YAHOO.lang.isArray(oNewPaginator.containers) &&
286 YAHOO.lang.isArray(oNewPaginator.dropdowns) &&
287 YAHOO.lang.isArray(oNewPaginator.links)) {
298 * @description True if built-in client-side pagination is enabled
302 this.setAttributeConfig("paginated", {
304 validator: YAHOO.lang.isBoolean,
305 method: function(oParam) {
306 var oPaginator = this.get("paginator");
307 var aContainerEls = oPaginator.containers;
309 // Paginator is enabled
311 // No containers found, create two from scratch
312 if(aContainerEls.length === 0) {
314 var pag0 = document.createElement("span");
315 pag0.id = this.id + "-paginator0";
316 YAHOO.util.Dom.addClass(pag0, YAHOO.widget.DataTable.CLASS_PAGINATOR);
317 pag0 = this._elContainer.insertBefore(pag0, this._elTable);
318 aContainerEls.push(pag0);
321 var pag1 = document.createElement("span");
322 pag1.id = this.id + "-paginator1";
323 YAHOO.util.Dom.addClass(pag1, YAHOO.widget.DataTable.CLASS_PAGINATOR);
324 pag1 = this._elContainer.insertBefore(pag1, this._elTable.nextSibling);
325 aContainerEls.push(pag1);
327 // Add containers directly to tracker
328 this._configs.paginator.value.containers = [pag0, pag1];
332 // Show each container
333 for(var i=0; i<aContainerEls.length; i++) {
334 aContainerEls[i].style.display = "";
339 if(oPaginator.pageLinks > -1) {
340 var aLinkEls = oPaginator.links;
341 // No links containers found, create from scratch
342 if(aLinkEls.length === 0) {
343 for(i=0; i<aContainerEls.length; i++) {
344 // Create one links container per Paginator container
345 var linkEl = document.createElement("span");
346 linkEl.id = "yui-dt-pagselect"+i;
347 linkEl = aContainerEls[i].appendChild(linkEl);
349 // Add event listener
351 YAHOO.util.Event.addListener(linkEl,"click",this._onPaginatorLinkClick,this);
353 // Add directly to tracker
354 this._configs.paginator.value.links.push(linkEl);
359 // Show these options in the dropdown
360 var dropdownOptions = oPaginator.dropdownOptions || [];
362 for(i=0; i<aContainerEls.length; i++) {
363 // Create one SELECT element per Paginator container
364 var selectEl = document.createElement("select");
365 YAHOO.util.Dom.addClass(selectEl, YAHOO.widget.DataTable.CLASS_DROPDOWN);
366 selectEl = aContainerEls[i].appendChild(selectEl);
367 selectEl.id = "yui-dt-pagselect"+i;
369 // Add event listener
371 YAHOO.util.Event.addListener(selectEl,"change",this._onPaginatorDropdownChange,this);
373 // Add DOM reference directly to tracker
374 this._configs.paginator.value.dropdowns.push(selectEl);
377 if(!oPaginator.dropdownOptions) {
378 selectEl.style.display = "none";
382 //TODO: fire paginatorDisabledEvent & add to api doc
383 YAHOO.log("Paginator enabled", "info", this.toString());
385 // Pagination is disabled
388 if(aContainerEls.length > 0) {
389 // Destroy or just hide?
391 // Hide each container
392 for(i=0; i<aContainerEls.length; i++) {
393 aContainerEls[i].style.display = "none";
397 // Destroy each container
398 for(i=0; i<aContainerEls.length; i++) {
399 YAHOO.util.Event.purgeElement(aContainerEls[i], true);
400 aContainerEls.innerHTML = null;
401 //TODO: remove container?
402 // aContainerEls[i].parentNode.removeChild(aContainerEls[i]);
406 //TODO: fire paginatorDisabledEvent & add to api doc
407 YAHOO.log("Paginator disabled", "info", this.toString());
414 * @description Value for the CAPTION element.
417 this.setAttributeConfig("caption", {
419 validator: YAHOO.lang.isString,
420 method: function(sCaption) {
421 // Create CAPTION element
422 if(!this._elCaption) {
423 if(!this._elTable.firstChild) {
424 this._elCaption = this._elTable.appendChild(document.createElement("caption"));
427 this._elCaption = this._elTable.insertBefore(document.createElement("caption"), this._elTable.firstChild);
431 this._elCaption.innerHTML = sCaption;
437 * @description True if primary TBODY should scroll while THEAD remains fixed.
438 * When enabling this feature, captions cannot be used, and the following
439 * features are not recommended: inline editing, resizeable columns.
443 this.setAttributeConfig("scrollable", {
445 validator: function(oParam) {
446 //TODO: validate agnst resizeable
447 return (YAHOO.lang.isBoolean(oParam) &&
448 // Not compatible with caption
449 !YAHOO.lang.isString(this.get("caption")));
451 method: function(oParam) {
454 YAHOO.util.Dom.addClass(this._elContainer,YAHOO.widget.DataTable.CLASS_SCROLLABLE);
455 YAHOO.util.Dom.addClass(this._elTbody,YAHOO.widget.DataTable.CLASS_SCROLLBODY);
458 YAHOO.util.Dom.removeClass(this._elContainer,YAHOO.widget.DataTable.CLASS_SCROLLABLE);
459 YAHOO.util.Dom.removeClass(this._elTbody,YAHOO.widget.DataTable.CLASS_SCROLLBODY);
466 /////////////////////////////////////////////////////////////////////////////
470 /////////////////////////////////////////////////////////////////////////////
473 * Class name assigned to TABLE element.
475 * @property DataTable.CLASS_TABLE
479 * @default "yui-dt-table"
481 YAHOO.widget.DataTable.CLASS_TABLE = "yui-dt-table";
484 * Class name assigned to header container elements within each TH element.
486 * @property DataTable.CLASS_HEADER
490 * @default "yui-dt-header"
492 YAHOO.widget.DataTable.CLASS_HEADER = "yui-dt-header";
495 * Class name assigned to the primary TBODY element.
497 * @property DataTable.CLASS_BODY
501 * @default "yui-dt-body"
503 YAHOO.widget.DataTable.CLASS_BODY = "yui-dt-body";
506 * Class name assigned to the scrolling TBODY element of a fixed scrolling DataTable.
508 * @property DataTable.CLASS_SCROLLBODY
512 * @default "yui-dt-scrollbody"
514 YAHOO.widget.DataTable.CLASS_SCROLLBODY = "yui-dt-scrollbody";
517 * Class name assigned to display label elements.
519 * @property DataTable.CLASS_LABEL
523 * @default "yui-dt-label"
525 YAHOO.widget.DataTable.CLASS_LABEL = "yui-dt-label";
528 * Class name assigned to resizer handle elements.
530 * @property DataTable.CLASS_RESIZER
534 * @default "yui-dt-resizer"
536 YAHOO.widget.DataTable.CLASS_RESIZER = "yui-dt-resizer";
539 * Class name assigned to Editor container elements.
541 * @property DataTable.CLASS_EDITOR
545 * @default "yui-dt-editor"
547 YAHOO.widget.DataTable.CLASS_EDITOR = "yui-dt-editor";
550 * Class name assigned to paginator container elements.
552 * @property DataTable.CLASS_PAGINATOR
556 * @default "yui-dt-paginator"
558 YAHOO.widget.DataTable.CLASS_PAGINATOR = "yui-dt-paginator";
561 * Class name assigned to page number indicators.
563 * @property DataTable.CLASS_PAGE
567 * @default "yui-dt-page"
569 YAHOO.widget.DataTable.CLASS_PAGE = "yui-dt-page";
572 * Class name assigned to default indicators.
574 * @property DataTable.CLASS_DEFAULT
578 * @default "yui-dt-default"
580 YAHOO.widget.DataTable.CLASS_DEFAULT = "yui-dt-default";
583 * Class name assigned to previous indicators.
585 * @property DataTable.CLASS_PREVIOUS
589 * @default "yui-dt-previous"
591 YAHOO.widget.DataTable.CLASS_PREVIOUS = "yui-dt-previous";
594 * Class name assigned next indicators.
596 * @property DataTable.CLASS_NEXT
600 * @default "yui-dt-next"
602 YAHOO.widget.DataTable.CLASS_NEXT = "yui-dt-next";
605 * Class name assigned to first elements.
607 * @property DataTable.CLASS_FIRST
611 * @default "yui-dt-first"
613 YAHOO.widget.DataTable.CLASS_FIRST = "yui-dt-first";
616 * Class name assigned to last elements.
618 * @property DataTable.CLASS_LAST
622 * @default "yui-dt-last"
624 YAHOO.widget.DataTable.CLASS_LAST = "yui-dt-last";
627 * Class name assigned to even elements.
629 * @property DataTable.CLASS_EVEN
633 * @default "yui-dt-even"
635 YAHOO.widget.DataTable.CLASS_EVEN = "yui-dt-even";
638 * Class name assigned to odd elements.
640 * @property DataTable.CLASS_ODD
644 * @default "yui-dt-odd"
646 YAHOO.widget.DataTable.CLASS_ODD = "yui-dt-odd";
649 * Class name assigned to selected elements.
651 * @property DataTable.CLASS_SELECTED
655 * @default "yui-dt-selected"
657 YAHOO.widget.DataTable.CLASS_SELECTED = "yui-dt-selected";
660 * Class name assigned to highlighted elements.
662 * @property DataTable.CLASS_HIGHLIGHTED
666 * @default "yui-dt-highlighted"
668 YAHOO.widget.DataTable.CLASS_HIGHLIGHTED = "yui-dt-highlighted";
671 * Class name assigned to disabled elements.
673 * @property DataTable.CLASS_DISABLED
677 * @default "yui-dt-disabled"
679 YAHOO.widget.DataTable.CLASS_DISABLED = "yui-dt-disabled";
682 * Class name assigned to empty indicators.
684 * @property DataTable.CLASS_EMPTY
688 * @default "yui-dt-empty"
690 YAHOO.widget.DataTable.CLASS_EMPTY = "yui-dt-empty";
693 * Class name assigned to loading indicatorx.
695 * @property DataTable.CLASS_LOADING
699 * @default "yui-dt-loading"
701 YAHOO.widget.DataTable.CLASS_LOADING = "yui-dt-loading";
704 * Class name assigned to error indicators.
706 * @property DataTable.CLASS_ERROR
710 * @default "yui-dt-error"
712 YAHOO.widget.DataTable.CLASS_ERROR = "yui-dt-error";
715 * Class name assigned to editable elements.
717 * @property DataTable.CLASS_EDITABLE
721 * @default "yui-dt-editable"
723 YAHOO.widget.DataTable.CLASS_EDITABLE = "yui-dt-editable";
726 * Class name assigned to scrollable elements.
728 * @property DataTable.CLASS_SCROLLABLE
732 * @default "yui-dt-scrollable"
734 YAHOO.widget.DataTable.CLASS_SCROLLABLE = "yui-dt-scrollable";
737 * Class name assigned to sortable elements.
739 * @property DataTable.CLASS_SORTABLE
743 * @default "yui-dt-sortable"
745 YAHOO.widget.DataTable.CLASS_SORTABLE = "yui-dt-sortable";
748 * Class name assigned to ascending elements.
750 * @property DataTable.CLASS_ASC
754 * @default "yui-dt-asc"
756 YAHOO.widget.DataTable.CLASS_ASC = "yui-dt-asc";
759 * Class name assigned to descending elements.
761 * @property DataTable.CLASS_DESC
765 * @default "yui-dt-desc"
767 YAHOO.widget.DataTable.CLASS_DESC = "yui-dt-desc";
770 * Class name assigned to BUTTON container elements.
772 * @property DataTable.CLASS_BUTTON
776 * @default "yui-dt-button"
778 YAHOO.widget.DataTable.CLASS_BUTTON = "yui-dt-button";
781 * Class name assigned to SELECT container elements.
783 * @property DataTable.CLASS_DROPDOWN
787 * @default "yui-dt-dropdown"
789 YAHOO.widget.DataTable.CLASS_DROPDOWN = "yui-dt-dropdown";
792 * Class name assigned to INPUT TYPE=CHECKBOX container elements.
794 * @property DataTable.CLASS_CHECKBOX
798 * @default "yui-dt-checkbox"
800 YAHOO.widget.DataTable.CLASS_CHECKBOX = "yui-dt-checkbox";
803 * Message to display if DataTable has no data.
805 * @property DataTable.MSG_EMPTY
809 * @default "No records found."
811 YAHOO.widget.DataTable.MSG_EMPTY = "No records found.";
814 * Message to display while DataTable is loading data.
816 * @property DataTable.MSG_LOADING
820 * @default "Loading data..."
822 YAHOO.widget.DataTable.MSG_LOADING = "Loading data...";
825 * Message to display while DataTable has data error.
827 * @property DataTable.MSG_ERROR
831 * @default "Data error."
833 YAHOO.widget.DataTable.MSG_ERROR = "Data error.";
835 /////////////////////////////////////////////////////////////////////////////
837 // Private member variables
839 /////////////////////////////////////////////////////////////////////////////
842 * Internal class variable for indexing multiple DataTable instances.
844 * @property DataTable._nCount
849 YAHOO.widget.DataTable._nCount = 0;
852 * Index assigned to instance.
858 YAHOO.widget.DataTable.prototype._nIndex = null;
861 * Counter for IDs assigned to TR elements.
863 * @property _nTrCount
867 YAHOO.widget.DataTable.prototype._nTrCount = 0;
870 * Unique name assigned to instance.
876 YAHOO.widget.DataTable.prototype._sName = null;
879 * DOM reference to the container element for the DataTable instance into which
880 * the TABLE element gets created.
882 * @property _elContainer
886 YAHOO.widget.DataTable.prototype._elContainer = null;
889 * DOM reference to the CAPTION element for the DataTable instance.
891 * @property _elCaption
895 YAHOO.widget.DataTable.prototype._elCaption = null;
898 * DOM reference to the TABLE element for the DataTable instance.
904 YAHOO.widget.DataTable.prototype._elTable = null;
907 * DOM reference to the THEAD element for the DataTable instance.
913 YAHOO.widget.DataTable.prototype._elThead = null;
916 * DOM reference to the primary TBODY element for the DataTable instance.
922 YAHOO.widget.DataTable.prototype._elTbody = null;
925 * DOM reference to the secondary TBODY element used to display DataTable messages.
927 * @property _elMsgTbody
931 YAHOO.widget.DataTable.prototype._elMsgTbody = null;
934 * DOM reference to the secondary TBODY element's single TR element used to display DataTable messages.
936 * @property _elMsgTbodyRow
940 YAHOO.widget.DataTable.prototype._elMsgTbodyRow = null;
943 * DOM reference to the secondary TBODY element's single TD element used to display DataTable messages.
945 * @property _elMsgTbodyCell
949 YAHOO.widget.DataTable.prototype._elMsgTbodyCell = null;
952 * DataSource instance for the DataTable instance.
954 * @property _oDataSource
955 * @type YAHOO.util.DataSource
958 YAHOO.widget.DataTable.prototype._oDataSource = null;
961 * ColumnSet instance for the DataTable instance.
963 * @property _oColumnSet
964 * @type YAHOO.widget.ColumnSet
967 YAHOO.widget.DataTable.prototype._oColumnSet = null;
970 * RecordSet instance for the DataTable instance.
972 * @property _oRecordSet
973 * @type YAHOO.widget.RecordSet
976 YAHOO.widget.DataTable.prototype._oRecordSet = null;
979 * ID string of first label link element of the current DataTable page, if any.
980 * Used for focusing sortable Columns with TAB.
982 * @property _sFirstLabelLinkId
986 YAHOO.widget.DataTable.prototype._sFirstLabelLinkId = null;
989 * ID string of first TR element of the current DataTable page.
991 * @property _sFirstTrId
995 YAHOO.widget.DataTable.prototype._sFirstTrId = null;
998 * ID string of the last TR element of the current DataTable page.
1000 * @property _sLastTrId
1004 YAHOO.widget.DataTable.prototype._sLastTrId = null;
1037 /////////////////////////////////////////////////////////////////////////////
1041 /////////////////////////////////////////////////////////////////////////////
1044 * Sets focus on the given element.
1047 * @param el {HTMLElement} Element.
1050 YAHOO.widget.DataTable.prototype._focusEl = function(el) {
1051 el = el || this._elTable;
1052 // http://developer.mozilla.org/en/docs/index.php?title=Key-navigable_custom_DHTML_widgets
1053 // The timeout is necessary in both IE and Firefox 1.5, to prevent scripts from doing
1054 // strange unexpected things as the user clicks on buttons and other controls.
1055 setTimeout(function() { el.focus(); },0);
1065 * Initializes container element.
1067 * @method _initContainerEl
1068 * @param elContainer {HTMLElement | String} HTML DIV element by reference or ID.
1071 YAHOO.widget.DataTable.prototype._initContainerEl = function(elContainer) {
1072 this._elContainer = null;
1073 elContainer = YAHOO.util.Dom.get(elContainer);
1074 if(elContainer && elContainer.tagName && (elContainer.tagName.toLowerCase() == "div")) {
1075 this._elContainer = elContainer;
1080 * Initializes object literal of config values.
1082 * @method _initConfigs
1083 * @param oConfig {Object} Object literal of config values.
1086 YAHOO.widget.DataTable.prototype._initConfigs = function(oConfigs) {
1088 if(oConfigs.constructor != Object) {
1090 YAHOO.log("Invalid configs", "warn", this.toString());
1092 // Backward compatibility
1093 else if(YAHOO.lang.isBoolean(oConfigs.paginator)) {
1094 YAHOO.log("DataTable's paginator model has been revised" +
1095 " -- please refer to the documentation for implementation" +
1096 " details", "warn", this.toString());
1098 this._oConfigs = oConfigs;
1103 * Initializes ColumnSet.
1105 * @method _initColumnSet
1106 * @param aColumnDefs {Object[]} Array of object literal Column definitions.
1109 YAHOO.widget.DataTable.prototype._initColumnSet = function(aColumnDefs) {
1110 this._oColumnSet = null;
1111 if(YAHOO.lang.isArray(aColumnDefs)) {
1112 this._oColumnSet = new YAHOO.widget.ColumnSet(aColumnDefs);
1114 // Backward compatibility
1115 else if(aColumnDefs instanceof YAHOO.widget.ColumnSet) {
1116 this._oColumnSet = aColumnDefs;
1117 YAHOO.log("DataTable's constructor now requires an array" +
1118 " of object literal Column definitions instead of a ColumnSet instance",
1119 "warn", this.toString());
1124 * Initializes DataSource.
1126 * @method _initDataSource
1127 * @param oDataSource {YAHOO.util.DataSource} DataSource instance.
1130 YAHOO.widget.DataTable.prototype._initDataSource = function(oDataSource) {
1131 this._oDataSource = null;
1132 if(oDataSource && (oDataSource instanceof YAHOO.util.DataSource)) {
1133 this._oDataSource = oDataSource;
1135 // Backward compatibility
1137 var tmpTable = null;
1138 var tmpContainer = this._elContainer;
1139 // Peek in container child nodes to see if TABLE already exists
1140 if(tmpContainer.hasChildNodes()) {
1141 var tmpChildren = tmpContainer.childNodes;
1142 for(i=0; i<tmpChildren.length; i++) {
1143 if(tmpChildren[i].tagName && tmpChildren[i].tagName.toLowerCase() == "table") {
1144 tmpTable = tmpChildren[i];
1149 var tmpFieldsArray = [];
1150 for(i=0; i<this._oColumnSet.keys.length; i++) {
1151 tmpFieldsArray.push({key:this._oColumnSet.keys[i].key});
1154 this._oDataSource = new YAHOO.util.DataSource(tmpTable);
1155 this._oDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
1156 this._oDataSource.responseSchema = {fields: tmpFieldsArray};
1157 YAHOO.log("Null DataSource for progressive enhancement from" +
1158 " markup has been deprecated", "warn", this.toString());
1165 * Initializes RecordSet.
1167 * @method _initRecordSet
1170 YAHOO.widget.DataTable.prototype._initRecordSet = function() {
1171 if(this._oRecordSet) {
1172 this._oRecordSet.reset();
1175 this._oRecordSet = new YAHOO.widget.RecordSet();
1180 * Creates HTML markup for TABLE, THEAD and TBODY elements.
1182 * @method _initTableEl
1185 YAHOO.widget.DataTable.prototype._initTableEl = function() {
1186 // Clear the container
1187 YAHOO.util.Event.purgeElement(this._elContainer, true);
1188 this._elContainer.innerHTML = "";
1191 this._elTable = this._elContainer.appendChild(document.createElement("table"));
1192 var elTable = this._elTable;
1193 elTable.tabIndex = 0;
1194 elTable.id = this.id + "-table";
1195 YAHOO.util.Dom.addClass(elTable, YAHOO.widget.DataTable.CLASS_TABLE);
1198 this._initTheadEl(elTable, this._oColumnSet);
1201 // Create TBODY for messages
1202 var elMsgTbody = document.createElement("tbody");
1203 var elMsgRow = elMsgTbody.appendChild(document.createElement("tr"));
1204 YAHOO.util.Dom.addClass(elMsgRow,YAHOO.widget.DataTable.CLASS_FIRST);
1205 YAHOO.util.Dom.addClass(elMsgRow,YAHOO.widget.DataTable.CLASS_LAST);
1206 this._elMsgRow = elMsgRow;
1207 var elMsgCell = elMsgRow.appendChild(document.createElement("td"));
1208 elMsgCell.colSpan = this._oColumnSet.keys.length;
1209 YAHOO.util.Dom.addClass(elMsgCell,YAHOO.widget.DataTable.CLASS_FIRST);
1210 YAHOO.util.Dom.addClass(elMsgCell,YAHOO.widget.DataTable.CLASS_LAST);
1211 this._elMsgTd = elMsgCell;
1212 this._elMsgTbody = elTable.appendChild(elMsgTbody);
1213 this.showTableMessage(YAHOO.widget.DataTable.MSG_LOADING, YAHOO.widget.DataTable.CLASS_LOADING);
1215 // Create TBODY for data
1216 this._elTbody = elTable.appendChild(document.createElement("tbody"));
1217 YAHOO.util.Dom.addClass(this._elTbody,YAHOO.widget.DataTable.CLASS_BODY);
1221 * Populates THEAD element with TH cells as defined by ColumnSet.
1223 * @method _initTheadEl
1226 YAHOO.widget.DataTable.prototype._initTheadEl = function() {
1227 var i,oColumn, colId;
1228 var oColumnSet = this._oColumnSet;
1229 this._sFirstLabelLinkId = null;
1232 var elThead = document.createElement("thead");
1234 // Iterate through each row of Column headers...
1235 var colTree = oColumnSet.tree;
1236 for(i=0; i<colTree.length; i++) {
1237 var elTheadRow = elThead.appendChild(document.createElement("tr"));
1238 elTheadRow.id = this.id+"-hdrow"+i;
1241 // ...and create THEAD cells
1242 for(var j=0; j<colTree[i].length; j++) {
1243 oColumn = colTree[i][j];
1244 colId = oColumn.getId();
1245 elTheadCell = elTheadRow.appendChild(document.createElement("th"));
1246 elTheadCell.id = this.id + "-col" + colId;
1247 this._initThEl(elTheadCell,oColumn,i,j);
1250 // Set FIRST/LAST on THEAD rows
1252 YAHOO.util.Dom.addClass(elTheadRow, YAHOO.widget.DataTable.CLASS_FIRST);
1254 if(i === (colTree.length-1)) {
1255 YAHOO.util.Dom.addClass(elTheadRow, YAHOO.widget.DataTable.CLASS_LAST);
1259 this._elThead = this._elTable.appendChild(elThead);
1261 // Set FIRST/LAST on THEAD cells using the values in ColumnSet headers array
1262 var aFirstHeaders = oColumnSet.headers[0].split(" ");
1263 var aLastHeaders = oColumnSet.headers[oColumnSet.headers.length-1].split(" ");
1264 for(i=0; i<aFirstHeaders.length; i++) {
1265 YAHOO.util.Dom.addClass(YAHOO.util.Dom.get(this.id+"-col"+aFirstHeaders[i]), YAHOO.widget.DataTable.CLASS_FIRST);
1267 for(i=0; i<aLastHeaders.length; i++) {
1268 YAHOO.util.Dom.addClass(YAHOO.util.Dom.get(this.id+"-col"+aLastHeaders[i]), YAHOO.widget.DataTable.CLASS_LAST);
1271 // Add Resizer only after DOM has been updated
1272 var foundDD = (YAHOO.util.DD) ? true : false;
1274 for(i=0; i<this._oColumnSet.keys.length; i++) {
1275 oColumn = this._oColumnSet.keys[i];
1276 colId = oColumn.getId();
1277 var elTheadCellId = YAHOO.util.Dom.get(this.id + "-col" + colId);
1278 if(oColumn.resizeable) {
1280 //TODO: fix fixed width tables
1281 // Skip the last column for fixed-width tables
1282 if(!this.fixedWidth || (this.fixedWidth &&
1283 (oColumn.getKeyIndex() != this._oColumnSet.keys.length-1))) {
1284 // TODO: better way to get elTheadContainer
1285 var elThContainer = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_HEADER,"div",elTheadCellId)[0];
1286 var elThResizer = elThContainer.appendChild(document.createElement("span"));
1287 elThResizer.id = this.id + "-resizer" + colId;
1288 YAHOO.util.Dom.addClass(elThResizer,YAHOO.widget.DataTable.CLASS_RESIZER);
1289 oColumn.ddResizer = new YAHOO.util.ColumnResizer(
1290 this, oColumn, elTheadCellId, elThResizer.id, elThResizer.id);
1291 var cancelClick = function(e) {
1292 YAHOO.util.Event.stopPropagation(e);
1294 YAHOO.util.Event.addListener(elThResizer,"click",cancelClick);
1296 if(this.fixedWidth) {
1297 //TODO: fix fixedWidth
1298 //elThContainer.style.overflow = "hidden";
1299 //TODO: better way to get elTheadText
1300 var elThLabel = (YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_LABEL,"span",elTheadCellId))[0];
1301 elThLabel.style.overflow = "hidden";
1310 YAHOO.log("Could not find DragDrop dependancy for resizeable Columns", "warn", this.toString());
1313 YAHOO.log("Column headers for " + this._oColumnSet.keys.length + " keys created","info",this.toString());
1317 * Populates TH cell as defined by Column.
1320 * @param elTheadCell {HTMLElement} TH cell element reference.
1321 * @param oColumn {YAHOO.widget.Column} Column object.
1322 * @param row {number} Row index.
1323 * @param col {number} Column index.
1326 YAHOO.widget.DataTable.prototype._initThEl = function(elTheadCell,oColumn,row,col) {
1327 // Clear out the cell of prior content
1328 // TODO: purgeListeners and other validation-related things
1329 var index = this._nIndex;
1330 var colId = oColumn.getId();
1331 elTheadCell.yuiColumnId = colId;
1333 elTheadCell.abbr = oColumn.abbr;
1336 elTheadCell.style.width = oColumn.width;
1340 if(YAHOO.lang.isString(oColumn.className)) {
1341 aCustomClasses = [oColumn.className];
1343 else if(YAHOO.lang.isArray(oColumn.className)) {
1344 aCustomClasses = oColumn.className;
1346 if(aCustomClasses) {
1347 for(var i=0; i<aCustomClasses.length; i++) {
1348 YAHOO.util.Dom.addClass(elTheadCell,aCustomClasses[i]);
1352 YAHOO.util.Dom.addClass(elTheadCell, "yui-dt-col-"+oColumn.key);
1354 elTheadCell.innerHTML = "";
1355 elTheadCell.rowSpan = oColumn.getRowspan();
1356 elTheadCell.colSpan = oColumn.getColspan();
1358 var elTheadContainer = elTheadCell.appendChild(document.createElement("div"));
1359 elTheadContainer.id = this.id + "-container" + colId;
1360 YAHOO.util.Dom.addClass(elTheadContainer,YAHOO.widget.DataTable.CLASS_HEADER);
1361 var elTheadLabel = elTheadContainer.appendChild(document.createElement("span"));
1362 elTheadLabel.id = this.id + "-label" + colId;
1363 YAHOO.util.Dom.addClass(elTheadLabel,YAHOO.widget.DataTable.CLASS_LABEL);
1365 var sLabel = YAHOO.lang.isValue(oColumn.label) ? oColumn.label : oColumn.key;
1366 if(oColumn.sortable) {
1367 YAHOO.util.Dom.addClass(elTheadCell,YAHOO.widget.DataTable.CLASS_SORTABLE);
1368 //TODO: Make sortLink customizeable
1369 //TODO: Make title configurable
1370 //TODO: Separate label from an accessibility link that says
1371 // "Click to sort ascending" and push it offscreen
1372 var sLabelLinkId = this.id + "-labellink" + colId;
1373 var sortLink = "?key=" + oColumn.key;
1374 elTheadLabel.innerHTML = "<a id=\"" + sLabelLinkId + "\" href=\"" + sortLink + "\" title=\"Click to sort\" class=\"" + YAHOO.widget.DataTable.CLASS_SORTABLE + "\">" + sLabel + "</a>";
1375 if(!this._sFirstLabelLinkId) {
1376 this._sFirstLabelLinkId = sLabelLinkId;
1380 elTheadLabel.innerHTML = sLabel;
1385 * Creates HTML markup for Cell Editor.
1387 * @method _initCellEditorEl
1390 YAHOO.widget.DataTable.prototype._initCellEditorEl = function() {
1391 // Attach Cell Editor container element to body
1392 var elCellEditor = document.createElement("div");
1393 elCellEditor.id = this.id + "-celleditor";
1394 elCellEditor.style.display = "none";
1395 YAHOO.util.Dom.addClass(elCellEditor, YAHOO.widget.DataTable.CLASS_EDITOR);
1396 elCellEditor = document.body.appendChild(elCellEditor);
1398 // Internal tracker of Cell Editor values
1399 var oCellEditor = {};
1400 oCellEditor.container = elCellEditor;
1401 oCellEditor.value = null;
1402 oCellEditor.isActive = false;
1403 this._oCellEditor = oCellEditor;
1406 this.subscribe("editorKeydownEvent", function(oArgs) {
1407 var e = oArgs.event;
1408 var elTarget = YAHOO.util.Event.getTarget(e);
1410 // ESC hides Cell Editor
1411 if((e.keyCode == 27)) {
1412 this.cancelCellEditor();
1418 * Initializes Column sorting.
1420 * @method _initColumnSort
1423 YAHOO.widget.DataTable.prototype._initColumnSort = function() {
1424 this.subscribe("headerCellClickEvent", this.onEventSortColumn);
1428 * Initializes DOM event listeners.
1430 * @method _initDomEvents
1433 YAHOO.widget.DataTable.prototype._initDomEvents = function() {
1434 var elTable = this._elTable;
1435 var elThead = this._elThead;
1436 var elTbody = this._elTbody;
1437 var elContainer = this._elContainer;
1439 YAHOO.util.Event.addListener(document, "click", this._onDocumentClick, this);
1440 YAHOO.util.Event.addListener(document, "keydown", this._onDocumentKeydown, this);
1442 YAHOO.util.Event.addListener(elTable, "focus", this._onTableFocus, this);
1443 YAHOO.util.Event.addListener(elTable, "mouseover", this._onTableMouseover, this);
1444 YAHOO.util.Event.addListener(elTable, "mouseout", this._onTableMouseout, this);
1445 YAHOO.util.Event.addListener(elTable, "mousedown", this._onTableMousedown, this);
1446 YAHOO.util.Event.addListener(elTable, "keydown", this._onTableKeydown, this);
1447 YAHOO.util.Event.addListener(elTable, "keypress", this._onTableKeypress, this);
1449 // Since we can't listen for click and dblclick on the same element...
1450 YAHOO.util.Event.addListener(elTable, "dblclick", this._onTableDblclick, this);
1451 YAHOO.util.Event.addListener(elThead, "click", this._onTheadClick, this);
1452 YAHOO.util.Event.addListener(elTbody, "click", this._onTbodyClick, this);
1454 YAHOO.util.Event.addListener(elContainer, "scroll", this._onScroll, this); // for IE
1455 YAHOO.util.Event.addListener(elTbody, "scroll", this._onScroll, this); // for everyone else
1494 // DOM MUTATION FUNCTIONS
1500 * Adds a TR element to the primary TBODY at the page row index if given, otherwise
1501 * at the end of the page. Formats TD elements within the TR element using data
1502 * from the given Record.
1505 * @param oRecord {YAHOO.widget.Record} Record instance.
1506 * @param index {Number} (optional) The page row index at which to add the TR
1508 * @return {String} ID of the added TR element, or null.
1511 YAHOO.widget.DataTable.prototype._addTrEl = function(oRecord, index) {
1512 this.hideTableMessage();
1514 // It's an append if no index provided, or index is negative or too big
1515 var append = (!YAHOO.lang.isNumber(index) || (index < 0) ||
1516 (index >= (this._elTbody.rows.length))) ? true : false;
1518 var oColumnSet = this._oColumnSet;
1519 var oRecordSet = this._oRecordSet;
1520 var isSortedBy = this.get("sortedBy");
1521 var sortedColKeyIndex = null;
1522 var sortedDir, newClass;
1524 sortedColKeyIndex = (isSortedBy.column) ?
1525 isSortedBy.column.getKeyIndex() :
1526 this._oColumnSet.getColumn(isSortedBy.key).getKeyIndex();
1527 sortedDir = isSortedBy.dir;
1528 newClass = (sortedDir === "desc") ? YAHOO.widget.DataTable.CLASS_DESC :
1529 YAHOO.widget.DataTable.CLASS_ASC;
1534 var elRow = (append) ? this._elTbody.appendChild(document.createElement("tr")) :
1535 this._elTbody.insertBefore(document.createElement("tr"),this._elTbody.rows[index]);
1537 elRow.id = this.id+"-bdrow"+this._nTrCount;
1539 elRow.yuiRecordId = oRecord.getId();
1542 for(var j=0; j<oColumnSet.keys.length; j++) {
1543 var oColumn = oColumnSet.keys[j];
1544 var elCell = elRow.appendChild(document.createElement("td"));
1545 elCell.id = elRow.id+"-cell"+j;
1546 elCell.yuiColumnId = oColumn.getId();
1547 elCell.headers = oColumnSet.headers[j];
1548 // For SF2 cellIndex bug: http://www.webreference.com/programming/javascript/ppk2/3.html
1549 elCell.yuiCellIndex = j;
1552 this.formatCell(elCell, oRecord, oColumn);
1554 // Set FIRST/LAST on TD
1556 YAHOO.util.Dom.addClass(elCell, YAHOO.widget.DataTable.CLASS_FIRST);
1558 else if (j === this._oColumnSet.keys.length-1) {
1559 YAHOO.util.Dom.addClass(elCell, YAHOO.widget.DataTable.CLASS_LAST);
1563 YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_ASC);
1564 YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_DESC);
1566 // Set ASC/DESC on TD
1567 if(j === sortedColKeyIndex) {
1568 newClass = (sortedDir === "desc") ?
1569 YAHOO.widget.DataTable.CLASS_DESC :
1570 YAHOO.widget.DataTable.CLASS_ASC;
1571 YAHOO.util.Dom.addClass(elCell, newClass);
1575 /*p.abx {word-wrap:break-word;}
1576 ought to solve the problem for Safari (the long words will wrap in your
1577 tds, instead of overflowing to the next td.
1578 (this is supported by IE win as well, so hide it if needed).
1580 One thing, though: it doesn't work in combination with
1581 'white-space:nowrap'.*/
1583 // need a div wrapper for safari?
1584 //TODO: fix fixedWidth
1585 if(this.fixedWidth) {
1586 elCell.style.overflow = "hidden";
1587 //elCell.style.width = "20px";
1595 * Formats all TD elements of given TR element with data from the given Record.
1597 * @method _updateTrEl
1598 * @param elRow {HTMLElement} The TR element to update.
1599 * @param oRecord {YAHOO.widget.Record} The associated Record instance.
1600 * @return {String} ID of the updated TR element, or null.
1603 YAHOO.widget.DataTable.prototype._updateTrEl = function(elRow, oRecord) {
1604 this.hideTableMessage();
1606 var isSortedBy = this.get("sortedBy");
1607 var sortedColKeyIndex = null;
1608 var sortedDir, newClass;
1610 sortedColKeyIndex = (isSortedBy.column) ?
1611 isSortedBy.column.getKeyIndex() :
1612 this._oColumnSet.getColumn(isSortedBy.key).getKeyIndex();
1613 sortedDir = isSortedBy.dir;
1614 newClass = (sortedDir === "desc") ? YAHOO.widget.DataTable.CLASS_DESC :
1615 YAHOO.widget.DataTable.CLASS_ASC;
1618 // Update TD elements with new data
1619 for(var j=0; j<elRow.cells.length; j++) {
1620 var oColumn = this._oColumnSet.keys[j];
1621 var elCell = elRow.cells[j];
1622 this.formatCell(elCell, oRecord, oColumn);
1625 YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_ASC);
1626 YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_DESC);
1628 // Set ASC/DESC on TD
1629 if(j === sortedColKeyIndex) {
1630 YAHOO.util.Dom.addClass(elCell, newClass);
1635 elRow.yuiRecordId = oRecord.getId();
1642 * Deletes TR element by DOM reference or by DataTable page row index.
1644 * @method _deleteTrEl
1645 * @param row {HTMLElement | Number} TR element reference or Datatable page row index.
1646 * @return {Boolean} Returns true if successful, else returns false.
1649 YAHOO.widget.DataTable.prototype._deleteTrEl = function(row) {
1652 // Get page row index for the element
1653 if(!YAHOO.lang.isNumber(row)) {
1654 rowIndex = YAHOO.util.Dom.get(row).sectionRowIndex;
1659 if(YAHOO.lang.isNumber(rowIndex) && (rowIndex > -2) && (rowIndex < this._elTbody.rows.length)) {
1660 this._elTbody.deleteRow(rowIndex);
1694 // CSS/STATE FUNCTIONS
1700 * Assigns the class YAHOO.widget.DataTable.CLASS_FIRST to the first TR element
1701 * of the DataTable page and updates internal tracker.
1703 * @method _setFirstRow
1706 YAHOO.widget.DataTable.prototype._setFirstRow = function() {
1707 var rowEl = this.getFirstTrEl();
1710 if(this._sFirstTrId) {
1711 YAHOO.util.Dom.removeClass(this._sFirstTrId, YAHOO.widget.DataTable.CLASS_FIRST);
1714 YAHOO.util.Dom.addClass(rowEl, YAHOO.widget.DataTable.CLASS_FIRST);
1715 this._sFirstTrId = rowEl.id;
1718 this._sFirstTrId = null;
1723 * Assigns the class YAHOO.widget.DataTable.CLASS_LAST to the last TR element
1724 * of the DataTable page and updates internal tracker.
1726 * @method _setLastRow
1729 YAHOO.widget.DataTable.prototype._setLastRow = function() {
1730 var rowEl = this.getLastTrEl();
1732 // Unassign previous class
1733 if(this._sLastTrId) {
1734 YAHOO.util.Dom.removeClass(this._sLastTrId, YAHOO.widget.DataTable.CLASS_LAST);
1737 YAHOO.util.Dom.addClass(rowEl, YAHOO.widget.DataTable.CLASS_LAST);
1738 this._sLastTrId = rowEl.id;
1741 this._sLastTrId = null;
1746 * Assigns the classes YAHOO.widget.DataTable.CLASS_EVEN and
1747 * YAHOO.widget.DataTable.CLASS_ODD to alternating TR elements of the DataTable
1748 * page. For performance, a subset of rows may be specified.
1750 * @method _setRowStripes
1751 * @param row {HTMLElement | String | Number} (optional) HTML TR element reference
1752 * or string ID, or page row index of where to start striping.
1753 * @param range {Number} (optional) If given, how many rows to stripe, otherwise
1754 * stripe all the rows until the end.
1757 YAHOO.widget.DataTable.prototype._setRowStripes = function(row, range) {
1758 // Default values stripe all rows
1759 var allRows = this._elTbody.rows;
1760 var nStartIndex = 0;
1761 var nEndIndex = allRows.length;
1764 if((row !== null) && (row !== undefined)) {
1765 // Validate given start row
1766 var elStartRow = this.getTrEl(row);
1768 nStartIndex = elStartRow.sectionRowIndex;
1770 // Validate given range
1771 if(YAHOO.lang.isNumber(range) && (range > 1)) {
1772 nEndIndex = nStartIndex + range;
1777 for(var i=nStartIndex; i<nEndIndex; i++) {
1779 YAHOO.util.Dom.removeClass(allRows[i], YAHOO.widget.DataTable.CLASS_EVEN);
1780 YAHOO.util.Dom.addClass(allRows[i], YAHOO.widget.DataTable.CLASS_ODD);
1783 YAHOO.util.Dom.removeClass(allRows[i], YAHOO.widget.DataTable.CLASS_ODD);
1784 YAHOO.util.Dom.addClass(allRows[i], YAHOO.widget.DataTable.CLASS_EVEN);
1833 /////////////////////////////////////////////////////////////////////////////
1835 // Private DOM Event Handlers
1837 /////////////////////////////////////////////////////////////////////////////
1840 * Handles scroll events on the CONTAINER (for IE) and TBODY elements (for everyone else).
1843 * @param e {HTMLEvent} The scroll event.
1844 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
1847 YAHOO.widget.DataTable.prototype._onScroll = function(e, oSelf) {
1848 var elTarget = YAHOO.util.Event.getTarget(e);
1849 var elTag = elTarget.tagName.toLowerCase();
1851 if(oSelf._oCellEditor.isActive) {
1852 oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
1853 oSelf.cancelCellEditor();
1856 oSelf.fireEvent("tableScrollEvent", {event:e, target:elTarget});
1860 * Handles click events on the DOCUMENT.
1862 * @method _onDocumentClick
1863 * @param e {HTMLEvent} The click event.
1864 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
1867 YAHOO.widget.DataTable.prototype._onDocumentClick = function(e, oSelf) {
1868 var elTarget = YAHOO.util.Event.getTarget(e);
1869 var elTag = elTarget.tagName.toLowerCase();
1871 if(!YAHOO.util.Dom.isAncestor(oSelf._elTable, elTarget)) {
1872 oSelf.fireEvent("tableBlurEvent");
1874 // Fires editorBlurEvent when click is not within the TABLE.
1875 // For cases when click is within the TABLE, due to timing issues,
1876 // the editorBlurEvent needs to get fired by the lower-level DOM click
1877 // handlers below rather than by the TABLE click handler directly.
1878 if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
1879 // Only if the click was not within the Cell Editor container
1880 if(!YAHOO.util.Dom.isAncestor(oSelf._oCellEditor.container, elTarget) &&
1881 (oSelf._oCellEditor.container.id !== elTarget.id)) {
1882 oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
1889 * Handles keydown events on the DOCUMENT.
1891 * @method _onDocumentKeydown
1892 * @param e {HTMLEvent} The keydown event.
1893 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
1896 YAHOO.widget.DataTable.prototype._onDocumentKeydown = function(e, oSelf) {
1897 var elTarget = YAHOO.util.Event.getTarget(e);
1898 var elTag = elTarget.tagName.toLowerCase();
1900 if(oSelf._oCellEditor && oSelf._oCellEditor.isActive &&
1901 YAHOO.util.Dom.isAncestor(oSelf._oCellEditor.container, elTarget)) {
1902 oSelf.fireEvent("editorKeydownEvent", {editor:oSelf._oCellEditor, event:e});
1907 * Handles focus events on the TABLE element.
1909 * @method _onTableFocus
1910 * @param e {HTMLEvent} The focus event.
1911 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
1914 YAHOO.widget.DataTable.prototype._onTableMouseover = function(e, oSelf) {
1915 oSelf.fireEvent("tableFocusEvent");
1919 * Handles mouseover events on the TABLE element.
1921 * @method _onTableMouseover
1922 * @param e {HTMLEvent} The mouseover event.
1923 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
1926 YAHOO.widget.DataTable.prototype._onTableMouseover = function(e, oSelf) {
1927 var elTarget = YAHOO.util.Event.getTarget(e);
1928 var elTag = elTarget.tagName.toLowerCase();
1930 while(elTarget && (elTag != "table")) {
1937 oSelf.fireEvent("cellMouseoverEvent",{target:elTarget,event:e});
1940 if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
1941 oSelf.fireEvent("headerLabelMouseoverEvent",{target:elTarget,event:e});
1945 oSelf.fireEvent("headerCellMouseoverEvent",{target:elTarget,event:e});
1948 if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
1949 oSelf.fireEvent("headerRowMouseoverEvent",{target:elTarget,event:e});
1952 oSelf.fireEvent("rowMouseoverEvent",{target:elTarget,event:e});
1958 elTarget = elTarget.parentNode;
1960 elTag = elTarget.tagName.toLowerCase();
1963 oSelf.fireEvent("tableMouseoverEvent",{target:(elTarget || oSelf._elTable),event:e});
1967 * Handles mouseout events on the TABLE element.
1969 * @method _onTableMouseout
1970 * @param e {HTMLEvent} The mouseout event.
1971 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
1974 YAHOO.widget.DataTable.prototype._onTableMouseout = function(e, oSelf) {
1975 var elTarget = YAHOO.util.Event.getTarget(e);
1976 var elTag = elTarget.tagName.toLowerCase();
1978 while(elTarget && (elTag != "table")) {
1985 oSelf.fireEvent("cellMouseoutEvent",{target:elTarget,event:e});
1988 if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
1989 oSelf.fireEvent("headerLabelMouseoutEvent",{target:elTarget,event:e});
1993 oSelf.fireEvent("headerCellMouseoutEvent",{target:elTarget,event:e});
1996 if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
1997 oSelf.fireEvent("headerRowMouseoutEvent",{target:elTarget,event:e});
2000 oSelf.fireEvent("rowMouseoutEvent",{target:elTarget,event:e});
2006 elTarget = elTarget.parentNode;
2008 elTag = elTarget.tagName.toLowerCase();
2011 oSelf.fireEvent("tableMouseoutEvent",{target:(elTarget || oSelf._elTable),event:e});
2015 * Handles mousedown events on the TABLE element.
2017 * @method _onTableMousedown
2018 * @param e {HTMLEvent} The mousedown event.
2019 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2022 YAHOO.widget.DataTable.prototype._onTableMousedown = function(e, oSelf) {
2023 var elTarget = YAHOO.util.Event.getTarget(e);
2024 var elTag = elTarget.tagName.toLowerCase();
2026 while(elTarget && (elTag != "table")) {
2033 oSelf.fireEvent("cellMousedownEvent",{target:elTarget,event:e});
2036 if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
2037 oSelf.fireEvent("headerLabelMousedownEvent",{target:elTarget,event:e});
2041 oSelf.fireEvent("headerCellMousedownEvent",{target:elTarget,event:e});
2044 if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
2045 oSelf.fireEvent("headerRowMousedownEvent",{target:elTarget,event:e});
2048 oSelf.fireEvent("rowMousedownEvent",{target:elTarget,event:e});
2054 elTarget = elTarget.parentNode;
2056 elTag = elTarget.tagName.toLowerCase();
2059 oSelf.fireEvent("tableMousedownEvent",{target:(elTarget || oSelf._elTable),event:e});
2063 * Handles dblclick events on the TABLE element.
2065 * @method _onTableDblclick
2066 * @param e {HTMLEvent} The dblclick event.
2067 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2070 YAHOO.widget.DataTable.prototype._onTableDblclick = function(e, oSelf) {
2071 var elTarget = YAHOO.util.Event.getTarget(e);
2072 var elTag = elTarget.tagName.toLowerCase();
2074 while(elTarget && (elTag != "table")) {
2079 oSelf.fireEvent("cellDblclickEvent",{target:elTarget,event:e});
2082 if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
2083 oSelf.fireEvent("headerLabelDblclickEvent",{target:elTarget,event:e});
2087 oSelf.fireEvent("headerCellDblclickEvent",{target:elTarget,event:e});
2090 if(elTarget.parentNode.tagName.toLowerCase() == "thead") {
2091 oSelf.fireEvent("headerRowDblclickEvent",{target:elTarget,event:e});
2094 oSelf.fireEvent("rowDblclickEvent",{target:elTarget,event:e});
2100 elTarget = elTarget.parentNode;
2102 elTag = elTarget.tagName.toLowerCase();
2105 oSelf.fireEvent("tableDblclickEvent",{target:(elTarget || oSelf._elTable),event:e});
2109 * Handles keydown events on the TABLE element. Handles arrow selection.
2111 * @method _onTableKeydown
2112 * @param e {HTMLEvent} The key event.
2113 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2116 YAHOO.widget.DataTable.prototype._onTableKeydown = function(e, oSelf) {
2117 var bSHIFT = e.shiftKey;
2118 var elTarget = YAHOO.util.Event.getTarget(e);
2120 // Ignore actions in the THEAD
2121 if(YAHOO.util.Dom.isAncestor(oSelf._elThead, elTarget)) {
2125 var nKey = YAHOO.util.Event.getCharCode(e);
2127 // TAB to first label link if any
2128 if(nKey === 9 && !bSHIFT && (elTarget.id === oSelf._elTable.id)) {
2129 if(oSelf._sFirstLabelLinkId) {
2130 YAHOO.util.Event.stopEvent(e);
2131 oSelf._focusEl(YAHOO.util.Dom.get(oSelf._sFirstLabelLinkId));
2136 // Something is currently selected
2137 var lastSelectedId = oSelf._sLastSelectedId;
2138 var lastSelectedEl = YAHOO.util.Dom.get(lastSelectedId);
2139 if(lastSelectedEl && oSelf.isSelected(lastSelectedEl)) {
2140 //TODO: handle tab, backspace, delete
2142 // Handle arrow selection
2143 if((nKey > 36) && (nKey < 41)) {
2144 YAHOO.util.Event.stopEvent(e);
2150 var sMode = oSelf.get("selectionMode");
2151 var allRows = oSelf._elTbody.rows;
2152 var anchorId = oSelf._sSelectionAnchorId;
2153 var anchorEl = YAHOO.util.Dom.get(anchorId);
2154 var newSelectedEl, trIndex, tdIndex, startIndex, endIndex, i, anchorPos;
2156 ////////////////////////////////////////////////////////////////////////
2158 // SHIFT cell block selection
2160 ////////////////////////////////////////////////////////////////////////
2161 if(bSHIFT && (sMode == "cellblock")) {
2162 trIndex = lastSelectedEl.parentNode.sectionRowIndex;
2163 tdIndex = lastSelectedEl.yuiCellIndex;
2167 // Is the anchor cell above, below, or same row
2168 if(anchorEl.parentNode.sectionRowIndex > trIndex) {
2171 else if(anchorEl.parentNode.sectionRowIndex < trIndex) {
2178 // Is the anchor cell left or right
2179 startIndex = Math.min(anchorEl.yuiCellIndex, tdIndex);
2180 endIndex = Math.max(anchorEl.yuiCellIndex, tdIndex);
2182 // Selecting away from anchor cell
2183 if(anchorPos <= 0) {
2184 // Select the horiz block on the next row
2185 if(trIndex < allRows.length-1) {
2186 for(i=startIndex; i<=endIndex; i++) {
2187 newSelectedEl = allRows[trIndex+1].cells[i];
2188 oSelf.selectCell(newSelectedEl);
2190 oSelf._sLastSelectedId = allRows[trIndex+1].cells[tdIndex].id;
2193 // Unselecting towards anchor cell
2195 // Unselect the horiz block on this row towards the next row
2196 for(i=startIndex; i<=endIndex; i++) {
2197 oSelf.unselectCell(allRows[trIndex].cells[i]);
2199 oSelf._sLastSelectedId = allRows[trIndex+1].cells[tdIndex].id;
2203 else if(nKey == 38) {
2204 // Is the anchor cell above, below, or same row
2205 if(anchorEl.parentNode.sectionRowIndex > trIndex) {
2208 else if(anchorEl.parentNode.sectionRowIndex < trIndex) {
2215 // Is the anchor cell left or right?
2216 startIndex = Math.min(anchorEl.yuiCellIndex, tdIndex);
2217 endIndex = Math.max(anchorEl.yuiCellIndex, tdIndex);
2219 // Selecting away from anchor cell
2220 if(anchorPos >= 0) {
2221 // Select the horiz block on the previous row
2223 for(i=startIndex; i<=endIndex; i++) {
2224 newSelectedEl = allRows[trIndex-1].cells[i];
2225 oSelf.selectCell(newSelectedEl);
2227 oSelf._sLastSelectedId = allRows[trIndex-1].cells[tdIndex].id;
2230 // Unselecting towards anchor cell
2232 // Unselect the horiz block on this row towards the previous row
2233 for(i=startIndex; i<=endIndex; i++) {
2234 oSelf.unselectCell(allRows[trIndex].cells[i]);
2236 oSelf._sLastSelectedId = allRows[trIndex-1].cells[tdIndex].id;
2240 else if(nKey == 39) {
2241 // Is the anchor cell left, right, or same column
2242 if(anchorEl.yuiCellIndex > tdIndex) {
2245 else if(anchorEl.yuiCellIndex < tdIndex) {
2252 // Selecting away from anchor cell
2253 if(anchorPos <= 0) {
2254 //Select the next vert block to the right
2255 if(tdIndex < allRows[trIndex].cells.length-1) {
2256 startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
2257 endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
2258 for(i=startIndex; i<=endIndex; i++) {
2259 newSelectedEl = allRows[i].cells[tdIndex+1];
2260 oSelf.selectCell(newSelectedEl);
2262 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
2265 // Unselecting towards anchor cell
2267 // Unselect the vert block on this column towards the right
2268 startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
2269 endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
2270 for(i=startIndex; i<=endIndex; i++) {
2271 oSelf.unselectCell(allRows[i].cells[tdIndex]);
2273 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
2277 else if(nKey == 37) {
2278 // Is the anchor cell left, right, or same column
2279 if(anchorEl.yuiCellIndex > tdIndex) {
2282 else if(anchorEl.yuiCellIndex < tdIndex) {
2289 // Selecting away from anchor cell
2290 if(anchorPos >= 0) {
2291 //Select the previous vert block to the left
2293 startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
2294 endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
2295 for(i=startIndex; i<=endIndex; i++) {
2296 newSelectedEl = allRows[i].cells[tdIndex-1];
2297 oSelf.selectCell(newSelectedEl);
2299 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
2302 // Unselecting towards anchor cell
2304 // Unselect the vert block on this column towards the left
2305 startIndex = Math.min(anchorEl.parentNode.sectionRowIndex, trIndex);
2306 endIndex = Math.max(anchorEl.parentNode.sectionRowIndex, trIndex);
2307 for(i=startIndex; i<=endIndex; i++) {
2308 oSelf.unselectCell(allRows[i].cells[tdIndex]);
2310 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
2314 ////////////////////////////////////////////////////////////////////////
2316 // SHIFT cell range selection
2318 ////////////////////////////////////////////////////////////////////////
2319 else if(bSHIFT && (sMode == "cellrange")) {
2320 trIndex = lastSelectedEl.parentNode.sectionRowIndex;
2321 tdIndex = lastSelectedEl.yuiCellIndex;
2323 // Is the anchor cell above, below, or same row
2324 if(anchorEl.parentNode.sectionRowIndex > trIndex) {
2327 else if(anchorEl.parentNode.sectionRowIndex < trIndex) {
2336 // Selecting away from anchor cell
2337 if(anchorPos <= 0) {
2338 // Select all cells to the end of this row
2339 for(i=tdIndex+1; i<allRows[trIndex].cells.length; i++){
2340 newSelectedEl = allRows[trIndex].cells[i];
2341 oSelf.selectCell(newSelectedEl);
2344 // Select some of the cells on the next row down
2345 if(trIndex < allRows.length-1) {
2346 for(i=0; i<=tdIndex; i++){
2347 newSelectedEl = allRows[trIndex+1].cells[i];
2348 oSelf.selectCell(newSelectedEl);
2352 // Unselecting towards anchor cell
2354 // Unselect all cells to the end of this row
2355 for(i=tdIndex; i<allRows[trIndex].cells.length; i++){
2356 oSelf.unselectCell(allRows[trIndex].cells[i]);
2359 // Unselect some of the cells on the next row down
2360 for(i=0; i<tdIndex; i++){
2361 oSelf.unselectCell(allRows[trIndex+1].cells[i]);
2363 oSelf._sLastSelectedId = allRows[trIndex+1].cells[tdIndex].id;
2367 else if(nKey == 38) {
2368 // Selecting away from anchor cell
2369 if(anchorPos >= 0) {
2370 // Select all the cells to the beginning of this row
2371 for(i=tdIndex-1; i>-1; i--){
2372 newSelectedEl = allRows[trIndex].cells[i];
2373 oSelf.selectCell(newSelectedEl);
2376 // Select some of the cells from the end of the previous row
2378 for(i=allRows[trIndex].cells.length-1; i>=tdIndex; i--){
2379 newSelectedEl = allRows[trIndex-1].cells[i];
2380 oSelf.selectCell(newSelectedEl);
2384 // Unselecting towards anchor cell
2386 // Unselect all the cells to the beginning of this row
2387 for(i=tdIndex; i>-1; i--){
2388 oSelf.unselectCell(allRows[trIndex].cells[i]);
2391 // Unselect some of the cells from the end of the previous row
2392 for(i=allRows[trIndex].cells.length-1; i>tdIndex; i--){
2393 oSelf.unselectCell(allRows[trIndex-1].cells[i]);
2395 oSelf._sLastSelectedId = allRows[trIndex-1].cells[tdIndex].id;
2399 else if(nKey == 39) {
2400 // Selecting away from anchor cell
2402 // Select the next cell to the right
2403 if(tdIndex < allRows[trIndex].cells.length-1) {
2404 newSelectedEl = allRows[trIndex].cells[tdIndex+1];
2405 oSelf.selectCell(newSelectedEl);
2407 // Select the first cell of the next row
2408 else if(trIndex < allRows.length-1) {
2409 newSelectedEl = allRows[trIndex+1].cells[0];
2410 oSelf.selectCell(newSelectedEl);
2413 // Unselecting towards anchor cell
2414 else if(anchorPos > 0) {
2415 oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);
2417 // Unselect this cell towards the right
2418 if(tdIndex < allRows[trIndex].cells.length-1) {
2419 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
2421 // Unselect this cells towards the first cell of the next row
2423 oSelf._sLastSelectedId = allRows[trIndex+1].cells[0].id;
2426 // Anchor is on this row
2428 // Selecting away from anchor
2429 if(anchorEl.yuiCellIndex <= tdIndex) {
2430 // Select the next cell to the right
2431 if(tdIndex < allRows[trIndex].cells.length-1) {
2432 newSelectedEl = allRows[trIndex].cells[tdIndex+1];
2433 oSelf.selectCell(newSelectedEl);
2435 // Select the first cell on the next row
2436 else if(trIndex < allRows.length-1){
2437 newSelectedEl = allRows[trIndex+1].cells[0];
2438 oSelf.selectCell(newSelectedEl);
2441 // Unselecting towards anchor
2443 // Unselect this cell towards the right
2444 oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);
2445 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex+1].id;
2450 else if(nKey == 37) {
2451 // Unselecting towards the anchor
2453 oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);
2455 // Unselect this cell towards the left
2457 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
2459 // Unselect this cell towards the last cell of the previous row
2461 oSelf._sLastSelectedId = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1].id;
2464 // Selecting towards the anchor
2465 else if(anchorPos > 0) {
2466 // Select the next cell to the left
2468 newSelectedEl = allRows[trIndex].cells[tdIndex-1];
2469 oSelf.selectCell(newSelectedEl);
2471 // Select the last cell of the previous row
2472 else if(trIndex > 0){
2473 newSelectedEl = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1];
2474 oSelf.selectCell(newSelectedEl);
2477 // Anchor is on this row
2479 // Selecting away from anchor cell
2480 if(anchorEl.yuiCellIndex >= tdIndex) {
2481 // Select the next cell to the left
2483 newSelectedEl = allRows[trIndex].cells[tdIndex-1];
2484 oSelf.selectCell(newSelectedEl);
2486 // Select the last cell of the previous row
2487 else if(trIndex > 0){
2488 newSelectedEl = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1];
2489 oSelf.selectCell(newSelectedEl);
2492 // Unselecting towards anchor cell
2494 oSelf.unselectCell(allRows[trIndex].cells[tdIndex]);
2496 // Unselect this cell towards the left
2498 oSelf._sLastSelectedId = allRows[trIndex].cells[tdIndex-1].id;
2500 // Unselect this cell towards the last cell of the previous row
2502 oSelf._sLastSelectedId = allRows[trIndex-1].cells[allRows[trIndex-1].cells.length-1].id;
2508 ////////////////////////////////////////////////////////////////////////
2510 // Simple single cell selection
2512 ////////////////////////////////////////////////////////////////////////
2513 else if((sMode == "cellblock") || (sMode == "cellrange") || (sMode == "singlecell")) {
2514 trIndex = lastSelectedEl.parentNode.sectionRowIndex;
2515 tdIndex = lastSelectedEl.yuiCellIndex;
2519 oSelf.unselectAllCells();
2521 // Select the next cell down
2522 if(trIndex < allRows.length-1) {
2523 newSelectedEl = allRows[trIndex+1].cells[tdIndex];
2524 oSelf.selectCell(newSelectedEl);
2526 // Select only the bottom cell
2528 newSelectedEl = lastSelectedEl;
2529 oSelf.selectCell(newSelectedEl);
2532 oSelf._sSelectionAnchorId = newSelectedEl.id;
2535 else if(nKey == 38) {
2536 oSelf.unselectAllCells();
2538 // Select the next cell up
2540 newSelectedEl = allRows[trIndex-1].cells[tdIndex];
2541 oSelf.selectCell(newSelectedEl);
2543 // Select only the top cell
2545 newSelectedEl = lastSelectedEl;
2546 oSelf.selectCell(newSelectedEl);
2549 oSelf._sSelectionAnchorId = newSelectedEl.id;
2552 else if(nKey == 39) {
2553 oSelf.unselectAllCells();
2555 // Select the next cell to the right
2556 if(tdIndex < lastSelectedEl.parentNode.cells.length-1) {
2557 newSelectedEl = lastSelectedEl.parentNode.cells[tdIndex+1];
2558 oSelf.selectCell(newSelectedEl);
2560 // Select only the right cell
2562 newSelectedEl = lastSelectedEl;
2563 oSelf.selectCell(newSelectedEl);
2566 oSelf._sSelectionAnchorId = newSelectedEl.id;
2569 else if(nKey == 37) {
2570 oSelf.unselectAllCells();
2572 // Select the next cell to the left
2574 newSelectedEl = lastSelectedEl.parentNode.cells[tdIndex-1];
2575 oSelf.selectCell(newSelectedEl);
2577 // Select only the left cell
2579 newSelectedEl = lastSelectedEl;
2580 oSelf.selectCell(newSelectedEl);
2583 oSelf._sSelectionAnchorId = newSelectedEl.id;
2586 ////////////////////////////////////////////////////////////////////////
2588 // SHIFT row selection
2590 ////////////////////////////////////////////////////////////////////////
2591 else if(bSHIFT && (sMode != "single")) {
2592 trIndex = lastSelectedEl.sectionRowIndex;
2594 if(anchorEl.sectionRowIndex > trIndex) {
2597 else if(anchorEl.sectionRowIndex < trIndex) {
2606 // Selecting away from anchor row
2607 if(anchorPos <= 0) {
2608 // Select the next row down
2609 if(trIndex < allRows.length-1) {
2610 oSelf.selectRow(trIndex+1);
2613 // Unselecting toward anchor row
2615 // Unselect this row towards the anchor row down
2616 oSelf.unselectRow(lastSelectedEl);
2617 oSelf._sLastSelectedId = allRows[trIndex+1].id;
2622 else if(nKey == 38) {
2623 // Selecting away from anchor row
2624 if(anchorPos >= 0) {
2625 // Select the next row up
2627 oSelf.selectRow(trIndex-1);
2630 // Unselect this row towards the anchor row up
2632 oSelf.unselectRow(lastSelectedEl);
2633 oSelf._sLastSelectedId = allRows[trIndex-1].id;
2637 else if(nKey == 39) {
2641 else if(nKey == 37) {
2645 ////////////////////////////////////////////////////////////////////////
2647 // Simple single row selection
2649 ////////////////////////////////////////////////////////////////////////
2651 trIndex = lastSelectedEl.sectionRowIndex;
2655 oSelf.unselectAllRows();
2657 // Select the next row
2658 if(trIndex < allRows.length-1) {
2659 newSelectedEl = allRows[trIndex+1];
2660 oSelf.selectRow(newSelectedEl);
2662 // Select only the last row
2664 newSelectedEl = lastSelectedEl;
2665 oSelf.selectRow(lastSelectedEl);
2668 oSelf._sSelectionAnchorId = newSelectedEl.id;
2671 else if(nKey == 38) {
2672 oSelf.unselectAllRows();
2674 // Select the previous row
2676 newSelectedEl = allRows[trIndex-1];
2677 oSelf.selectRow(newSelectedEl);
2679 // Select only the first row
2681 newSelectedEl = lastSelectedEl;
2682 oSelf.selectRow(newSelectedEl);
2685 oSelf._sSelectionAnchorId = newSelectedEl.id;
2688 else if(nKey == 39) {
2692 else if(nKey == 37) {
2700 * Handles keypress events on the TABLE. Mainly to support stopEvent on Mac.
2702 * @method _onTableKeypress
2703 * @param e {HTMLEvent} The key event.
2704 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2707 YAHOO.widget.DataTable.prototype._onTableKeypress = function(e, oSelf) {
2708 var isMac = (navigator.userAgent.toLowerCase().indexOf("mac") != -1);
2710 var nKey = YAHOO.util.Event.getCharCode(e);
2713 YAHOO.util.Event.stopEvent(e);
2716 else if(nKey == 38) {
2717 YAHOO.util.Event.stopEvent(e);
2723 * Handles click events on the THEAD element.
2725 * @method _onTheadClick
2726 * @param e {HTMLEvent} The click event.
2727 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2730 YAHOO.widget.DataTable.prototype._onTheadClick = function(e, oSelf) {
2731 var elTarget = YAHOO.util.Event.getTarget(e);
2732 var elTag = elTarget.tagName.toLowerCase();
2734 if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
2735 oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
2738 while(elTarget && (elTag != "thead")) {
2743 if(YAHOO.util.Dom.hasClass(elTarget, YAHOO.widget.DataTable.CLASS_LABEL)) {
2744 oSelf.fireEvent("headerLabelClickEvent",{target:elTarget,event:e});
2748 oSelf.fireEvent("headerCellClickEvent",{target:elTarget,event:e});
2751 oSelf.fireEvent("headerRowClickEvent",{target:elTarget,event:e});
2756 elTarget = elTarget.parentNode;
2758 elTag = elTarget.tagName.toLowerCase();
2761 oSelf.fireEvent("tableClickEvent",{target:(elTarget || oSelf._elTable),event:e});
2765 * Handles click events on the primary TBODY element.
2767 * @method _onTbodyClick
2768 * @param e {HTMLEvent} The click event.
2769 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2772 YAHOO.widget.DataTable.prototype._onTbodyClick = function(e, oSelf) {
2773 var elTarget = YAHOO.util.Event.getTarget(e);
2774 var elTag = elTarget.tagName.toLowerCase();
2776 if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
2777 oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
2780 while(elTarget && (elTag != "table")) {
2785 if(elTarget.type.toLowerCase() == "checkbox") {
2786 oSelf.fireEvent("checkboxClickEvent",{target:elTarget,event:e});
2788 else if(elTarget.type.toLowerCase() == "radio") {
2789 oSelf.fireEvent("radioClickEvent",{target:elTarget,event:e});
2793 oSelf.fireEvent("linkClickEvent",{target:elTarget,event:e});
2796 oSelf.fireEvent("buttonClickEvent",{target:elTarget,event:e});
2799 oSelf.fireEvent("cellClickEvent",{target:elTarget,event:e});
2802 oSelf.fireEvent("rowClickEvent",{target:elTarget,event:e});
2807 elTarget = elTarget.parentNode;
2809 elTag = elTarget.tagName.toLowerCase();
2812 oSelf.fireEvent("tableClickEvent",{target:(elTarget || oSelf._elTable),event:e});
2816 * Handles keyup events on the TBODY. Executes deletion.
2818 * @method _onTbodyKeyup
2819 * @param e {HTMLEvent} The key event.
2820 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2823 /*YAHOO.widget.DataTable.prototype._onTbodyKeyup = function(e, oSelf) {
2824 var nKey = YAHOO.util.Event.getCharCode(e);
2826 if(nKey == 46) {//TODO: if something is selected
2832 * Handles click events on paginator links.
2834 * @method _onPaginatorLinkClick
2835 * @param e {HTMLEvent} The click event.
2836 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2839 YAHOO.widget.DataTable.prototype._onPaginatorLinkClick = function(e, oSelf) {
2840 var elTarget = YAHOO.util.Event.getTarget(e);
2841 var elTag = elTarget.tagName.toLowerCase();
2843 if(oSelf._oCellEditor && oSelf._oCellEditor.isActive) {
2844 oSelf.fireEvent("editorBlurEvent", {editor:oSelf._oCellEditor});
2847 while(elTarget && (elTag != "table")) {
2852 YAHOO.util.Event.stopEvent(e);
2853 //TODO: after the showPage call, figure out which link
2854 //TODO: was clicked and reset focus to the new version of it
2855 switch(elTarget.className) {
2856 case YAHOO.widget.DataTable.CLASS_PAGE:
2857 oSelf.showPage(parseInt(elTarget.innerHTML,10));
2859 case YAHOO.widget.DataTable.CLASS_FIRST:
2862 case YAHOO.widget.DataTable.CLASS_LAST:
2863 oSelf.showPage(oSelf.get("paginator").totalPages);
2865 case YAHOO.widget.DataTable.CLASS_PREVIOUS:
2866 oSelf.showPage(oSelf.get("paginator").currentPage - 1);
2868 case YAHOO.widget.DataTable.CLASS_NEXT:
2869 oSelf.showPage(oSelf.get("paginator").currentPage + 1);
2876 elTarget = elTarget.parentNode;
2878 elTag = elTarget.tagName.toLowerCase();
2887 * Handles change events on paginator SELECT element.
2889 * @method _onPaginatorDropdownChange
2890 * @param e {HTMLEvent} The change event.
2891 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2894 YAHOO.widget.DataTable.prototype._onPaginatorDropdownChange = function(e, oSelf) {
2895 var elTarget = YAHOO.util.Event.getTarget(e);
2896 var newValue = elTarget[elTarget.selectedIndex].value;
2898 var newRowsPerPage = YAHOO.lang.isValue(parseInt(newValue,10)) ? parseInt(newValue,10) : null;
2899 if(newRowsPerPage !== null) {
2900 var newStartRecordIndex = (oSelf.get("paginator").currentPage-1) * newRowsPerPage;
2901 oSelf.updatePaginator({rowsPerPage:newRowsPerPage, startRecordIndex:newStartRecordIndex});
2902 oSelf.refreshView();
2905 YAHOO.log("Could not paginate with " + newValue + " rows per page", "error", oSelf.toString());
2910 * Handles change events on SELECT elements within DataTable.
2912 * @method _onDropdownChange
2913 * @param e {HTMLEvent} The change event.
2914 * @param oSelf {YAHOO.widget.DataTable} DataTable instance.
2917 YAHOO.widget.DataTable.prototype._onDropdownChange = function(e, oSelf) {
2918 var elTarget = YAHOO.util.Event.getTarget(e);
2919 //TODO: pass what args?
2920 //var value = elTarget[elTarget.selectedIndex].value;
2921 oSelf.fireEvent("dropdownChangeEvent", {event:e, target:elTarget});
2962 /////////////////////////////////////////////////////////////////////////////
2964 // Public member variables
2966 /////////////////////////////////////////////////////////////////////////////
2969 /////////////////////////////////////////////////////////////////////////////
2973 /////////////////////////////////////////////////////////////////////////////
2978 * Public accessor to the unique name of the DataSource instance.
2981 * @return {String} Unique name of the DataSource instance.
2984 YAHOO.widget.DataTable.prototype.toString = function() {
2985 return "DataTable " + this._sName;
2989 * Returns the DataTable instance's DataSource instance.
2991 * @method getDataSource
2992 * @return {YAHOO.util.DataSource} DataSource instance.
2994 YAHOO.widget.DataTable.prototype.getDataSource = function() {
2995 return this._oDataSource;
2999 * Returns the DataTable instance's ColumnSet instance.
3001 * @method getColumnSet
3002 * @return {YAHOO.widget.ColumnSet} ColumnSet instance.
3004 YAHOO.widget.DataTable.prototype.getColumnSet = function() {
3005 return this._oColumnSet;
3009 * Returns the DataTable instance's RecordSet instance.
3011 * @method getRecordSet
3012 * @return {YAHOO.widget.RecordSet} RecordSet instance.
3014 YAHOO.widget.DataTable.prototype.getRecordSet = function() {
3015 return this._oRecordSet;
3019 * Returns the DataTable instance's Cell Editor as an object literal with the
3020 * following properties:
3023 * <dd>Cell element being edited</dd>
3026 * <dd>Associated Column instance</dd>
3028 * <dt>container</dt>
3029 * <dd>Reference to editor's container DIV element</dd>
3032 * <dd>True if cell is currently being edited</dd>
3035 * <dd>Associated Record instance</dd>
3037 * <dt>validator</dt>
3038 * <dd>Associated validator function</dd>
3041 * <dd>Current input value</dd>
3049 * @method getCellEditor
3050 * @return {Object} Cell Editor object literal values.
3052 YAHOO.widget.DataTable.prototype.getCellEditor = function() {
3053 return this._oCellEditor;
3101 * Returns DOM reference to the DataTable's TABLE element.
3103 * @method getTableEl
3104 * @return {HTMLElement} Reference to TABLE element.
3106 YAHOO.widget.DataTable.prototype.getTableEl = function() {
3107 return this._elTable;
3111 * Returns DOM reference to the DataTable's THEAD element.
3113 * @method getTheadEl
3114 * @return {HTMLElement} Reference to THEAD element.
3116 YAHOO.widget.DataTable.prototype.getTheadEl = function() {
3117 return this._elThead;
3121 * Returns DOM reference to the DataTable's primary TBODY element.
3123 * @method getTbodyEl
3124 * @return {HTMLElement} Reference to TBODY element.
3126 YAHOO.widget.DataTable.prototype.getTbodyEl = function() {
3127 return this._elTbody;
3129 // Backward compatibility
3130 YAHOO.widget.DataTable.prototype.getBody = function() {
3131 YAHOO.log("The method getBody() has been deprecated" +
3132 " in favor of getTbodyEl()", "warn", this.toString());
3133 return this.getTbodyEl();
3137 * Returns DOM reference to the DataTable's secondary TBODY element that is
3138 * used to display messages.
3140 * @method getMsgTbodyEl
3141 * @return {HTMLElement} Reference to TBODY element.
3143 YAHOO.widget.DataTable.prototype.getMsgTbodyEl = function() {
3144 return this._elMsgTbody;
3148 * Returns DOM reference to the TD element within the secondary TBODY that is
3149 * used to display messages.
3151 * @method getMsgTdEl
3152 * @return {HTMLElement} Reference to TD element.
3154 YAHOO.widget.DataTable.prototype.getMsgTdEl = function() {
3155 return this._elMsgTd;
3159 * Returns the corresponding TR reference for a given DOM element, ID string or
3160 * directly page row index. If the given identifier is a child of a TR element,
3161 * then DOM tree is traversed until a parent TR element is returned, otherwise
3165 * @param row {HTMLElement | String | Number | YAHOO.widget.Record} Which row to
3166 * get: by element reference, ID string, page row index, or Record.
3167 * @return {HTMLElement} Reference to TR element, or null.
3169 YAHOO.widget.DataTable.prototype.getTrEl = function(row) {
3170 var allRows = this._elTbody.rows;
3173 if(row instanceof YAHOO.widget.Record) {
3174 var nTrIndex = this.getTrIndex(row);
3175 return allRows[nTrIndex];
3177 // By page row index
3178 else if(YAHOO.lang.isNumber(row) && (row > -1) && (row < allRows.length)) {
3179 return allRows[row];
3181 // By ID string or element reference
3184 var el = YAHOO.util.Dom.get(row);
3186 // Validate HTML element
3187 if(el && (el.ownerDocument == document)) {
3188 // Validate TR element
3189 if(el.tagName.toLowerCase() != "tr") {
3190 // Traverse up the DOM to find the corresponding TR element
3191 elRow = YAHOO.util.Dom.getAncestorByTagName(el,"tr");
3197 // Make sure the TR is in this TBODY
3198 if(elRow && (elRow.parentNode == this._elTbody)) {
3199 // Now we can return the TR element
3205 YAHOO.log("Could not get TR element for row " + row, "warn", this.toString());
3208 // Backward compatibility
3209 YAHOO.widget.DataTable.prototype.getRow = function(index) {
3210 YAHOO.log("The method getRow() has been deprecated" +
3211 " in favor of getTrEl()", "warn", this.toString());
3212 return this.getTrEl(index);
3216 * Returns DOM reference to the first TR element in the DataTable page, or null.
3218 * @method getFirstTrEl
3219 * @return {HTMLElement} Reference to TR element.
3221 YAHOO.widget.DataTable.prototype.getFirstTrEl = function() {
3222 return this._elTbody.rows[0] || null;
3226 * Returns DOM reference to the last TR element in the DataTable page, or null.
3228 * @method getLastTrEl
3229 * @return {HTMLElement} Reference to last TR element.
3231 YAHOO.widget.DataTable.prototype.getLastTrEl = function() {
3232 var allRows = this._elTbody.rows;
3233 if(allRows.length > 0) {
3234 return allRows[allRows.length-1] || null;
3239 * Returns DOM reference to the given TD element.
3242 * @param cell {HTMLElement | String} DOM element reference or string ID.
3243 * @return {HTMLElement} Reference to TD element.
3245 YAHOO.widget.DataTable.prototype.getTdEl = function(cell) {
3247 var el = YAHOO.util.Dom.get(cell);
3249 // Validate HTML element
3250 if(el && (el.ownerDocument == document)) {
3251 // Validate TD element
3252 if(el.tagName.toLowerCase() != "td") {
3253 // Traverse up the DOM to find the corresponding TR element
3254 elCell = YAHOO.util.Dom.getAncestorByTagName(el, "td");
3260 // Make sure the TD is in this TBODY
3261 if(elCell && (elCell.parentNode.parentNode == this._elTbody)) {
3262 // Now we can return the TD element
3267 YAHOO.log("Could not get TD element for cell " + cell, "warn", this.toString());
3272 * Returns DOM reference to the TH element at given DataTable page coordinates, or null.
3275 * @param header {HTMLElement | String | YAHOO.widget.Column} DOM element
3276 * reference or string ID, or Column instance.
3277 * @return {HTMLElement} Reference to TH element.
3279 YAHOO.widget.DataTable.prototype.getThEl = function(header) {
3282 // Validate Column instance
3283 if(header instanceof YAHOO.widget.Column) {
3284 var oColumn = header;
3285 elHeader = YAHOO.util.Dom.get(this.id + "-col" + oColumn.getId());
3290 // Validate HTML element
3292 var el = YAHOO.util.Dom.get(header);
3294 if(el && (el.ownerDocument == document)) {
3295 // Validate TH element
3296 if(el.tagName.toLowerCase() != "th") {
3297 // Traverse up the DOM to find the corresponding TR element
3298 elHeader = YAHOO.util.Dom.getAncestorByTagName(el,"th");
3304 // Make sure the TH is in this THEAD
3305 if(elHeader && (elHeader.parentNode.parentNode == this._elThead)) {
3306 // Now we can return the TD element
3312 YAHOO.log("Could not get TH element for header " + header, "warn", this.toString());
3317 * Returns the page row index of given row. Returns null if the row is not in
3318 * view on the current DataTable page.
3320 * @method getTrIndex
3321 * @param row {HTMLElement | String | YAHOO.widget.Record | Number} DOM or ID
3322 * string reference to an element within the DataTable page, a Record instance,
3323 * or a Record's RecordSet index.
3324 * @return {Number} Page row index, or null if row does not exist or is not in view.
3326 YAHOO.widget.DataTable.prototype.getTrIndex = function(row) {
3330 if(row instanceof YAHOO.widget.Record) {
3331 nRecordIndex = this._oRecordSet.getRecordIndex(row);
3333 // Calculate page row index from Record index
3334 else if(YAHOO.lang.isNumber(row)) {
3337 if(YAHOO.lang.isNumber(nRecordIndex)) {
3338 // DataTable is paginated
3339 if(this.get("paginated")) {
3340 // Get the first and last Record on this page
3341 var startRecordIndex = this.get("paginator").startRecordIndex;
3342 var endRecordIndex = startRecordIndex + this.get("paginator").rowsPerPage - 1;
3343 // This Record is in view
3344 if((nRecordIndex >= startRecordIndex) && (nRecordIndex <= endRecordIndex)) {
3345 return nRecordIndex - startRecordIndex;
3347 // This Record is not in view
3352 // Not paginated, just return the Record index
3354 return nRecordIndex;
3358 // By element reference or ID string
3360 // Validate TR element
3361 elRow = this.getTrEl(row);
3362 if(elRow && (elRow.ownerDocument == document) &&
3363 (elRow.parentNode == this._elTbody)) {
3364 return elRow.sectionRowIndex;
3368 YAHOO.log("Could not get page row index for row " + row, "warn", this.toString());
3420 * Resets a RecordSet with the given data and populates the page view
3421 * with the new data. Any previous data and selection states are cleared.
3422 * However, sort states are not cleared, so if the given data is in a particular
3423 * sort order, implementers should take care to reset the sortedBy property. If
3424 * pagination is enabled, the currentPage is shown and Paginator UI updated,
3425 * otherwise all rows are displayed as a single page. For performance, existing
3426 * DOM elements are reused when possible.
3428 * @method initializeTable
3429 * @param oData {Object | Object[]} An object literal of data or an array of
3430 * object literals containing data.
3432 YAHOO.widget.DataTable.prototype.initializeTable = function(oData) {
3433 // Clear the RecordSet
3434 this._oRecordSet.reset();
3436 // Add data to RecordSet
3437 var records = this._oRecordSet.addRecords(oData);
3440 this._unselectAllTrEls();
3441 this._unselectAllTdEls();
3442 this._aSelections = null;
3443 this._sLastSelectedId = null;
3444 this._sSelectionAnchorId = null;
3448 this.fireEvent("initEvent");
3452 * Refreshes the view with existing Records from the RecordSet while
3453 * maintaining sort, pagination, and selection states. For performance, reuses
3454 * existing DOM elements when possible while deleting extraneous elements.
3456 * @method refreshView
3458 YAHOO.widget.DataTable.prototype.refreshView = function() {
3459 var i, j, k, l, aRecords;
3460 var oPaginator = this.updatePaginator();
3462 // Paginator is enabled, show a subset of Records and update Paginator UI
3463 if(this.get("paginated")) {
3464 var rowsPerPage = oPaginator.rowsPerPage;
3465 var startRecordIndex = (oPaginator.currentPage - 1) * rowsPerPage;
3466 aRecords = this._oRecordSet.getRecords(startRecordIndex, rowsPerPage);
3467 this.formatPaginators();
3471 aRecords = this._oRecordSet.getRecords();
3474 var elTbody = this._elTbody;
3475 var elRows = elTbody.rows;
3478 if(YAHOO.lang.isArray(aRecords) && (aRecords.length > 0)) {
3479 this.hideTableMessage();
3481 // Keep track of selected rows
3482 var aSelectedRows = this.getSelectedRows();
3483 // Keep track of selected cells
3484 var aSelectedCells = this.getSelectedCells();
3485 // Anything to reinstate?
3486 var bReselect = (aSelectedRows.length>0) || (aSelectedCells.length > 0);
3488 // Remove extra rows from the bottom so as to preserve ID order
3489 while(elTbody.hasChildNodes() && (elRows.length > aRecords.length)) {
3490 elTbody.deleteRow(-1);
3493 // Unselect all TR and TD elements in the UI
3495 this._unselectAllTrEls();
3496 this._unselectAllTdEls();
3499 // From the top, update in-place existing rows
3500 for(i=0; i<elRows.length; i++) {
3501 this._updateTrEl(elRows[i], aRecords[i]);
3504 // Add TR elements as necessary
3505 for(i=elRows.length; i<aRecords.length; i++) {
3506 this._addTrEl(aRecords[i]);
3509 // Reinstate selected and sorted classes
3510 var allRows = elTbody.rows;
3512 // Loop over each row
3513 for(j=0; j<allRows.length; j++) {
3514 var thisRow = allRows[j];
3515 var sMode = this.get("selectionMode");
3516 if ((sMode == "standard") || (sMode == "single")) {
3518 for(k=0; k<aSelectedRows.length; k++) {
3519 if(aSelectedRows[k] === thisRow.yuiRecordId) {
3520 YAHOO.util.Dom.addClass(thisRow, YAHOO.widget.DataTable.CLASS_SELECTED);
3521 if(j === allRows.length-1) {
3522 this._sLastSelectedId = thisRow.id;
3523 this._sSelectionAnchorId = thisRow.id;
3529 // Loop over each cell
3530 for(k=0; k<thisRow.cells.length; k++) {
3531 var thisCell = thisRow.cells[k];
3533 for(l=0; l<aSelectedCells.length; l++) {
3534 if((aSelectedCells[l].recordId === thisRow.yuiRecordId) &&
3535 (aSelectedCells[l].columnId === thisCell.yuiColumnId)) {
3536 YAHOO.util.Dom.addClass(thisCell, YAHOO.widget.DataTable.CLASS_SELECTED);
3537 if(k === thisRow.cells.length-1) {
3538 this._sLastSelectedId = thisCell.id;
3539 this._sSelectionAnchorId = thisCell.id;
3548 // Set FIRST/LAST, EVEN/ODD
3549 this._setFirstRow();
3551 this._setRowStripes();
3553 this.fireEvent("refreshEvent");
3554 YAHOO.log("DataTable showing " + aRecords.length + " of " + this._oRecordSet.getLength() + " rows", "info", this.toString());
3559 while(elTbody.hasChildNodes()) {
3560 elTbody.deleteRow(-1);
3563 this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
3568 * Nulls out the entire DataTable instance and related objects, removes attached
3569 * event listeners, and clears out DOM elements inside the container. After
3570 * calling this method, the instance reference should be expliclitly nulled by
3571 * implementer, as in myDataTable = null. Use with caution!
3575 YAHOO.widget.DataTable.prototype.destroy = function() {
3576 // Destroy Cell Editor
3577 YAHOO.util.Event.purgeElement(this._oCellEditor.container, true);
3578 document.body.removeChild(this._oCellEditor.container);
3580 var instanceName = this.toString();
3581 var elContainer = this._elContainer;
3583 // Unhook custom events
3584 this._oRecordSet.unsubscribeAll();
3585 this.unsubscribeAll();
3587 // Unhook DOM events
3588 YAHOO.util.Event.purgeElement(elContainer, true);
3590 // Remove DOM elements
3591 elContainer.innerHTML = "";
3594 for(var param in this) {
3595 if(this.hasOwnProperty(param)) {
3600 YAHOO.log("DataTable instance destroyed: " + instanceName);
3604 * Displays message within secondary TBODY.
3606 * @method showTableMessage
3607 * @param sHTML {String} (optional) Value for innerHTML.
3608 * @param sClassName {String} (optional) Classname.
3610 YAHOO.widget.DataTable.prototype.showTableMessage = function(sHTML, sClassName) {
3611 var elCell = this._elMsgTd;
3612 if(YAHOO.lang.isString(sHTML)) {
3613 elCell.innerHTML = sHTML;
3615 if(YAHOO.lang.isString(sClassName)) {
3616 YAHOO.util.Dom.addClass(elCell, sClassName);
3618 this._elMsgTbody.style.display = "";
3619 this.fireEvent("tableMsgShowEvent", {html:sHTML, className:sClassName});
3620 YAHOO.log("DataTable showing message: " + sHTML, "info", this.toString());
3624 * Hides secondary TBODY.
3626 * @method hideTableMessage
3628 YAHOO.widget.DataTable.prototype.hideTableMessage = function() {
3629 if(this._elMsgTbody.style.display != "none") {
3630 this._elMsgTbody.style.display = "none";
3631 this.fireEvent("tableMsgHideEvent");
3632 YAHOO.log("DataTable message hidden", "info", this.toString());
3637 * Brings focus to DataTable instance.
3641 YAHOO.widget.DataTable.prototype.focus = function() {
3642 this._focusEl(this._elTable);
3710 // RECORDSET FUNCTIONS
3713 * Returns Record index for given TR element or page row index.
3715 * @method getRecordIndex
3716 * @param row {YAHOO.widget.Record | HTMLElement | Number} Record instance, TR
3717 * element reference or page row index.
3718 * @return {Number} Record's RecordSet index, or null.
3720 YAHOO.widget.DataTable.prototype.getRecordIndex = function(row) {
3723 if(!YAHOO.lang.isNumber(row)) {
3725 if(row instanceof YAHOO.widget.Record) {
3726 return this._oRecordSet.getRecordIndex(row);
3728 // By element reference
3730 // Find the TR element
3731 var el = this.getTrEl(row);
3733 nTrIndex = el.sectionRowIndex;
3737 // By page row index
3742 if(YAHOO.lang.isNumber(nTrIndex)) {
3743 if(this.get("paginated")) {
3744 return this.get("paginator").startRecordIndex + nTrIndex;
3751 YAHOO.log("Could not get Record index for row " + row, "warn", this.toString());
3756 * For the given identifier, returns the associated Record instance.
3759 * @param row {HTMLElement | String | Number} RecordSet position index, DOM
3760 * reference or ID string to an element within the DataTable page.
3761 * @return {YAHOO.widget.Record} Record instance.
3763 YAHOO.widget.DataTable.prototype.getRecord = function(row) {
3764 var nRecordIndex = row;
3766 // By element reference or ID string
3767 if(!YAHOO.lang.isNumber(nRecordIndex)) {
3768 // Validate TR element
3769 var elRow = this.getTrEl(row);
3771 nRecordIndex = this.getRecordIndex(row);
3775 if(YAHOO.lang.isNumber(nRecordIndex)) {
3776 return this._oRecordSet.getRecord(nRecordIndex);
3779 YAHOO.log("Could not get Record for row at " + row, "warn", this.toString());
3831 * For the given identifier, returns the associated Column instance.
3834 * @param column {HTMLElement | String | Number} ColumnSet.keys position index, DOM
3835 * reference or ID string to an element within the DataTable page.
3836 * @return {YAHOO.widget.Column} Column instance.
3838 YAHOO.widget.DataTable.prototype.getColumn = function(column) {
3839 var nColumnIndex = column;
3841 // By element reference or ID string
3842 if(!YAHOO.lang.isNumber(nColumnIndex)) {
3843 // Validate TD element
3844 var elCell = this.getTdEl(column);
3846 nColumnIndex = elCell.yuiColumnId;
3848 // Validate TH element
3850 elCell = this.getThEl(column);
3852 nColumnIndex = elCell.yuiColumnId;
3858 if(YAHOO.lang.isNumber(nColumnIndex)) {
3859 return this._oColumnSet.getColumn(nColumnIndex);
3862 YAHOO.log("Could not get Column for column at " + column, "warn", this.toString());
3867 * Sorts given Column.
3869 * @method sortColumn
3870 * @param oColumn {YAHOO.widget.Column} Column instance.
3872 YAHOO.widget.DataTable.prototype.sortColumn = function(oColumn) {
3876 if(!oColumn instanceof YAHOO.widget.Column) {
3877 //TODO: accept the TH or TH.key
3878 //TODO: Get the column based on TH.yuiColumnId
3881 if(oColumn.sortable) {
3882 // What is the default sort direction?
3883 var sortDir = (oColumn.sortOptions && oColumn.sortOptions.defaultOrder) ? oColumn.sortOptions.defaultOrder : "asc";
3886 var oSortedBy = this.get("sortedBy");
3887 if(oSortedBy && (oSortedBy.key === oColumn.key)) {
3889 sortDir = (oSortedBy.dir == "asc") ? "desc" : "asc";
3892 sortDir = (sortDir == "asc") ? "desc" : "asc";
3896 // Is there a custom sort handler function defined?
3897 var sortFnc = (oColumn.sortOptions && YAHOO.lang.isFunction(oColumn.sortOptions.sortFunction)) ?
3898 oColumn.sortOptions.sortFunction : function(a, b, desc) {
3899 var sorted = YAHOO.util.Sort.compare(a.getData(oColumn.key),b.getData(oColumn.key), desc);
3901 return YAHOO.util.Sort.compare(a.getId(),b.getId(), desc);
3908 // Do the actual sort
3909 var desc = (sortDir == "desc") ? true : false;
3910 this._oRecordSet.sortRecords(sortFnc, desc);
3912 // Update sortedBy tracker
3913 this.set("sortedBy", {key:oColumn.key, dir:sortDir, column:oColumn});
3915 // Reset to first page
3916 //TODO: Keep selection in view
3917 this.updatePaginator({currentPage:1});
3922 this.fireEvent("columnSortEvent",{column:oColumn,dir:sortDir});
3923 YAHOO.log("Column \"" + oColumn.key + "\" sorted \"" + sortDir + "\"", "info", this.toString());
3927 YAHOO.log("Column is not sortable", "info", this.toString());
3979 * Adds one new Record of data into the RecordSet at the index if given,
3980 * otherwise at the end. If the new Record is in page view, the
3981 * corresponding DOM elements are also updated.
3984 * @param oData {Object} Object literal of data for the row.
3985 * @param index {Number} (optional) RecordSet position index at which to add data.
3987 YAHOO.widget.DataTable.prototype.addRow = function(oData, index) {
3988 if(oData && (oData.constructor == Object)) {
3989 var oRecord = this._oRecordSet.addRecord(oData, index);
3991 var nTrIndex = this.getTrIndex(oRecord);
3994 if(YAHOO.lang.isNumber(nTrIndex)) {
3995 // Paginated so just refresh the view to keep pagination state
3996 if(this.get("paginated")) {
3999 // Add the TR element
4001 var newTrId = this._addTrEl(oRecord, nTrIndex);
4003 // Is this an insert or an append?
4004 var append = (YAHOO.lang.isNumber(nTrIndex) &&
4005 (nTrIndex == this._elTbody.rows.length-1)) ? true : false;
4007 // Stripe the one new row
4009 if((this._elTbody.rows.length-1)%2) {
4010 YAHOO.util.Dom.addClass(newTrId, YAHOO.widget.DataTable.CLASS_ODD);
4013 YAHOO.util.Dom.addClass(newTrId, YAHOO.widget.DataTable.CLASS_EVEN);
4016 // Restripe all the rows after the new one
4018 this._setRowStripes(nTrIndex);
4021 // If new row is at the bottom
4025 // If new row is at the top
4026 else if(YAHOO.lang.isNumber(index) && (nTrIndex === 0)) {
4027 this._setFirstRow();
4032 // Record is not in view so just update pagination UI
4034 this.updatePaginator();
4037 // TODO: what args to pass?
4038 this.fireEvent("rowAddEvent", {record:oRecord});
4041 nTrIndex = (YAHOO.lang.isValue(nTrIndex))? nTrIndex : "n/a";
4043 YAHOO.log("Added row: Record ID = " + oRecord.getId() +
4044 ", Record index = " + this.getRecordIndex(oRecord) +
4045 ", page row index = " + nTrIndex, "info", this.toString());
4049 YAHOO.log("Could not add row with " + YAHOO.lang.dump(oData), "error", this.toString());
4053 * Convenience method to add multiple rows.
4056 * @param aData {Object[]} Array of object literal data for the rows.
4057 * @param index {Number} (optional) RecordSet position index at which to add data.
4059 YAHOO.widget.DataTable.prototype.addRows = function(aData, index) {
4060 if(YAHOO.lang.isArray(aData)) {
4062 if(YAHOO.lang.isNumber(index)) {
4063 for(i=aData.length-1; i>-1; i--) {
4064 this.addRow(aData[i], index);
4068 for(i=0; i<aData.length; i++) {
4069 this.addRow(aData[i]);
4074 YAHOO.log("Could not add rows " + YAHOO.lang.dump(aData));
4079 * For the given row, updates the associated Record with the given data. If the
4080 * row is in view, the corresponding DOM elements are also updated.
4083 * @param row {YAHOO.widget.Record | Number | HTMLElement | String}
4084 * Which row to update: By Record instance, by Record's RecordSet
4085 * position index, by HTMLElement reference to the TR element, or by ID string
4086 * of the TR element.
4087 * @param oData {Object} Object literal of data for the row.
4089 YAHOO.widget.DataTable.prototype.updateRow = function(row, oData) {
4090 var oldRecord, updatedRecord, elRow;
4092 // Get the Record directly
4093 if((row instanceof YAHOO.widget.Record) || (YAHOO.lang.isNumber(row))) {
4094 // Get the Record directly
4095 oldRecord = this._oRecordSet.getRecord(row);
4097 // Is this row in view?
4098 elRow = this.getTrEl(oldRecord);
4100 // Get the Record by TR element
4102 elRow = this.getTrEl(row);
4104 oldRecord = this._oRecordSet.getRecord(this.getRecordIndex(elRow));
4108 // Update the Record
4110 // Copy data from the Record for the event that gets fired later
4111 var oRecordData = oldRecord.getData();
4113 for(var param in oRecordData) {
4114 oldData[param] = oRecordData[param];
4117 updatedRecord = this._oRecordSet.updateRecord(oldRecord, oData);
4120 YAHOO.log("Could not update row " + row + " with the data : " +
4121 YAHOO.lang.dump(oData), "error", this.toString());
4126 // Update the TR only if row is in view
4128 this._updateTrEl(elRow, updatedRecord);
4131 this.fireEvent("rowUpdateEvent", {record:updatedRecord, oldData:oldData});
4132 YAHOO.log("DataTable row updated: Record ID = " + updatedRecord.getId() +
4133 ", Record index = " + this.getRecordIndex(updatedRecord) +
4134 ", page row index = " + this.getTrIndex(updatedRecord), "info", this.toString());
4138 * Deletes the given row's Record from the RecordSet. If the row is in view, the
4139 * corresponding DOM elements are also deleted.
4142 * @param row {HTMLElement | String | Number} DOM element reference or ID string
4143 * to DataTable page element or RecordSet index.
4145 YAHOO.widget.DataTable.prototype.deleteRow = function(row) {
4146 // Get the Record index...
4147 var nRecordIndex = null;
4148 // ...by Record index
4149 if(YAHOO.lang.isNumber(row)) {
4152 // ...by element reference
4154 var elRow = YAHOO.util.Dom.get(row);
4155 elRow = this.getTrEl(elRow);
4157 nRecordIndex = this.getRecordIndex(elRow);
4160 if(nRecordIndex !== null) {
4161 var oRecord = this._oRecordSet.getRecord(nRecordIndex);
4163 var nRecordId = oRecord.getId();
4165 // Remove from selection tracker if there
4166 var tracker = this._aSelections || [];
4167 for(var j=0; j<tracker.length; j++) {
4168 if((YAHOO.lang.isNumber(tracker[j]) && (tracker[j] === nRecordId)) ||
4169 ((tracker[j].constructor == Object) && (tracker[j].recordId === nRecordId))) {
4170 tracker.splice(j,1);
4174 // Copy data from the Record for the event that gets fired later
4175 var oRecordData = oRecord.getData();
4177 for(var param in oRecordData) {
4178 oData[param] = oRecordData[param];
4181 // Delete Record from RecordSet
4182 this._oRecordSet.deleteRecord(nRecordIndex);
4184 // If row is in view, delete the TR element
4185 var nTrIndex = this.getTrIndex(nRecordIndex);
4186 if(YAHOO.lang.isNumber(nTrIndex)) {
4187 var isLast = (nTrIndex == this.getLastTrEl().sectionRowIndex) ?
4189 this._deleteTrEl(nTrIndex);
4192 if(this._elTbody.rows.length === 0) {
4193 this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
4198 if(nTrIndex === 0) {
4199 this._setFirstRow();
4205 if(nTrIndex != this._elTbody.rows.length) {
4206 this._setRowStripes(nTrIndex);
4211 this.fireEvent("rowDeleteEvent", {recordIndex:nRecordIndex,
4212 oldData:oData, trElIndex:nTrIndex});
4213 YAHOO.log("DataTable row deleted: Record ID = " + nRecordId +
4214 ", Record index = " + nRecordIndex +
4215 ", page row index = " + nTrIndex, "info", this.toString());
4219 YAHOO.log("Could not delete row: " + row, "warn", this.toString());
4224 * Convenience method to delete multiple rows.
4226 * @method deleteRows
4227 * @param row {HTMLElement | String | Number} DOM element reference or ID string
4228 * to DataTable page element or RecordSet index.
4229 * @param count {Number} (optional) How many rows to delete. A negative value
4230 * will delete towards the beginning.
4232 YAHOO.widget.DataTable.prototype.deleteRows = function(row, count) {
4233 // Get the Record index...
4234 var nRecordIndex = null;
4235 // ...by Record index
4236 if(YAHOO.lang.isNumber(row)) {
4239 // ...by element reference
4241 var elRow = YAHOO.util.Dom.get(row);
4242 elRow = this.getTrEl(elRow);
4244 nRecordIndex = this.getRecordIndex(elRow);
4247 if(nRecordIndex !== null) {
4248 if(count && YAHOO.lang.isNumber(count)) {
4249 // Start with highest index and work down
4250 var startIndex = (count > 0) ? nRecordIndex + count -1 : nRecordIndex;
4251 var endIndex = (count > 0) ? nRecordIndex : nRecordIndex + count + 1;
4252 for(var i=startIndex; i>endIndex-1; i--) {
4257 this.deleteRow(nRecordIndex);
4261 YAHOO.log("Could not delete row " + row, "info", this.toString());
4313 * Outputs markup into the given TD based on given Record.
4315 * @method formatCell
4316 * @param elCell {HTMLElement} TD Element.
4317 * @param oRecord {YAHOO.widget.Record} (Optional) Record instance.
4318 * @param oColumn {YAHOO.widget.Column} (Optional) Column instance.
4319 * @return {HTML} Markup.
4321 YAHOO.widget.DataTable.prototype.formatCell = function(elCell, oRecord, oColumn) {
4322 if(!(oRecord instanceof YAHOO.widget.Record)) {
4323 oRecord = this.getRecord(elCell);
4325 if(!(oColumn instanceof YAHOO.widget.Column)) {
4326 oColumn = this._oColumnSet.getColumn(elCell.yuiColumnId);
4329 if(oRecord && oColumn) {
4330 var oData = oRecord.getData(oColumn.key);
4333 if(YAHOO.lang.isString(oColumn.formatter)) {
4334 switch(oColumn.formatter) {
4336 fnFormatter = YAHOO.widget.DataTable.formatButton;
4339 fnFormatter = YAHOO.widget.DataTable.formatCheckbox;
4342 fnFormatter = YAHOO.widget.DataTable.formatCurrency;
4345 fnFormatter = YAHOO.widget.DataTable.formatDate;
4348 fnFormatter = YAHOO.widget.DataTable.formatDropdown;
4351 fnFormatter = YAHOO.widget.DataTable.formatEmail;
4354 fnFormatter = YAHOO.widget.DataTable.formatLink;
4357 fnFormatter = YAHOO.widget.DataTable.formatNumber;
4360 fnFormatter = YAHOO.widget.DataTable.formatRadio;
4363 fnFormatter = YAHOO.widget.DataTable.formatText;
4366 fnFormatter = YAHOO.widget.DataTable.formatTextarea;
4369 fnFormatter = YAHOO.widget.DataTable.formatTextbox;
4372 // This is the default
4375 YAHOO.log("Could not find formatter function \"" +
4376 oColumn.formatter + "\"", "warn", this.toString());
4380 else if(YAHOO.lang.isFunction(oColumn.formatter)) {
4381 fnFormatter = oColumn.formatter;
4384 // Apply special formatter
4386 fnFormatter.call(this, elCell, oRecord, oColumn, oData);
4389 elCell.innerHTML = (YAHOO.lang.isValue(oData)) ? oData.toString() : "";
4392 // Add custom classNames
4393 var aCustomClasses = null;
4394 if(YAHOO.lang.isString(oColumn.className)) {
4395 aCustomClasses = [oColumn.className];
4397 else if(YAHOO.lang.isArray(oColumn.className)) {
4398 aCustomClasses = oColumn.className;
4400 if(aCustomClasses) {
4401 for(var i=0; i<aCustomClasses.length; i++) {
4402 YAHOO.util.Dom.addClass(elCell, aCustomClasses[i]);
4406 YAHOO.util.Dom.addClass(elCell, "yui-dt-col-"+oColumn.key);
4409 if(oColumn.editor) {
4410 YAHOO.util.Dom.addClass(elCell,YAHOO.widget.DataTable.CLASS_EDITABLE);
4413 this.fireEvent("cellFormatEvent", {record:oRecord, key:oColumn.key, el:elCell});
4416 YAHOO.log("Could not format cell " + elCell, "error", this.toString());
4422 * Formats a BUTTON element.
4424 * @method DataTable.formatButton
4425 * @param el {HTMLElement} The element to format with markup.
4426 * @param oRecord {YAHOO.widget.Record} Record instance.
4427 * @param oColumn {YAHOO.widget.Column} Column instance.
4428 * @param oData {Object | Boolean} Data value for the cell. By default, the value
4429 * is what gets written to the BUTTON.
4432 YAHOO.widget.DataTable.formatButton= function(el, oRecord, oColumn, oData) {
4433 var sValue = YAHOO.lang.isValue(oData) ? oData : "Click";
4434 //TODO: support YAHOO.widget.Button
4435 //if(YAHOO.widget.Button) {
4439 el.innerHTML = "<button type=\"button\" class=\""+
4440 YAHOO.widget.DataTable.CLASS_BUTTON + "\">" + sValue + "</button>";
4445 * Formats a CHECKBOX element.
4447 * @method DataTable.formatCheckbox
4448 * @param el {HTMLElement} The element to format with markup.
4449 * @param oRecord {YAHOO.widget.Record} Record instance.
4450 * @param oColumn {YAHOO.widget.Column} Column instance.
4451 * @param oData {Object | Boolean} Data value for the cell. Can be a simple
4452 * Boolean to indicate whether checkbox is checked or not. Can be object literal
4453 * {checked:bBoolean, label:sLabel}. Other forms of oData require a custom
4457 YAHOO.widget.DataTable.formatCheckbox = function(el, oRecord, oColumn, oData) {
4458 var bChecked = oData;
4459 bChecked = (bChecked) ? " checked" : "";
4460 el.innerHTML = "<input type=\"checkbox\"" + bChecked +
4461 " class=\"" + YAHOO.widget.DataTable.CLASS_CHECKBOX + "\">";
4465 * Formats currency. Default unit is USD.
4467 * @method DataTable.formatCurrency
4468 * @param el {HTMLElement} The element to format with markup.
4469 * @param oRecord {YAHOO.widget.Record} Record instance.
4470 * @param oColumn {YAHOO.widget.Column} Column instance.
4471 * @param oData {Number} Data value for the cell.
4474 YAHOO.widget.DataTable.formatCurrency = function(el, oRecord, oColumn, oData) {
4475 if(YAHOO.lang.isNumber(oData)) {
4476 var nAmount = oData;
4479 // Round to the penny
4480 nAmount = Math.round(nAmount*100)/100;
4482 // Default currency is USD
4483 markup = "$"+nAmount;
4486 var dotIndex = markup.indexOf(".");
4491 while(dotIndex > markup.length-3) {
4495 el.innerHTML = markup;
4498 el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
4503 * Formats JavaScript Dates.
4505 * @method DataTable.formatDate
4506 * @param el {HTMLElement} The element to format with markup.
4507 * @param oRecord {YAHOO.widget.Record} Record instance.
4508 * @param oColumn {YAHOO.widget.Column} Column instance.
4509 * @param oData {Object} Data value for the cell, or null.
4512 YAHOO.widget.DataTable.formatDate = function(el, oRecord, oColumn, oData) {
4514 if(oDate instanceof Date) {
4515 el.innerHTML = (oDate.getMonth()+1) + "/" + oDate.getDate() + "/" + oDate.getFullYear();
4518 el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
4523 * Formats SELECT elements.
4525 * @method DataTable.formatDropdown
4526 * @param el {HTMLElement} The element to format with markup.
4527 * @param oRecord {YAHOO.widget.Record} Record instance.
4528 * @param oColumn {YAHOO.widget.Column} Column instance.
4529 * @param oData {Object} Data value for the cell, or null.
4532 YAHOO.widget.DataTable.formatDropdown = function(el, oRecord, oColumn, oData) {
4533 var selectedValue = (YAHOO.lang.isValue(oData)) ? oData : oRecord.getData(oColumn.key);
4534 var options = (YAHOO.lang.isArray(oColumn.dropdownOptions)) ?
4535 oColumn.dropdownOptions : null;
4538 var collection = el.getElementsByTagName("select");
4540 // Create the form element only once, so we can attach the onChange listener
4541 if(collection.length === 0) {
4542 // Create SELECT element
4543 selectEl = document.createElement("select");
4544 YAHOO.util.Dom.addClass(selectEl, YAHOO.widget.DataTable.CLASS_DROPDOWN);
4545 selectEl = el.appendChild(selectEl);
4547 // Add event listener
4548 //TODO: static method doesn't have access to the datatable instance...
4549 YAHOO.util.Event.addListener(selectEl,"change",oDataTable._onDropdownChange,oDataTable);
4552 selectEl = collection[0];
4554 // Update the form element
4556 // Clear out previous options
4557 selectEl.innerHTML = "";
4559 // We have options to populate
4561 // Create OPTION elements
4562 for(var i=0; i<options.length; i++) {
4563 var option = options[i];
4564 var optionEl = document.createElement("option");
4565 optionEl.value = (YAHOO.lang.isValue(option.value)) ?
4566 option.value : option;
4567 optionEl.innerHTML = (YAHOO.lang.isValue(option.text)) ?
4568 option.text : option;
4569 optionEl = selectEl.appendChild(optionEl);
4572 // Selected value is our only option
4574 selectEl.innerHTML = "<option value=\"" + selectedValue + "\">" + selectedValue + "</option>";
4578 el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
4585 * @method DataTable.formatEmail
4586 * @param el {HTMLElement} The element to format with markup.
4587 * @param oRecord {YAHOO.widget.Record} Record instance.
4588 * @param oColumn {YAHOO.widget.Column} Column instance.
4589 * @param oData {Object} Data value for the cell, or null.
4592 YAHOO.widget.DataTable.formatEmail = function(el, oRecord, oColumn, oData) {
4593 if(YAHOO.lang.isString(oData)) {
4594 el.innerHTML = "<a href=\"mailto:" + oData + "\">" + oData + "</a>";
4597 el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
4604 * @method DataTable.formatLink
4605 * @param el {HTMLElement} The element to format with markup.
4606 * @param oRecord {YAHOO.widget.Record} Record instance.
4607 * @param oColumn {YAHOO.widget.Column} Column instance.
4608 * @param oData {Object} Data value for the cell, or null.
4611 YAHOO.widget.DataTable.formatLink = function(el, oRecord, oColumn, oData) {
4612 if(YAHOO.lang.isString(oData)) {
4613 el.innerHTML = "<a href=\"" + oData + "\">" + oData + "</a>";
4616 el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
4623 * @method DataTable.formatNumber
4624 * @param el {HTMLElement} The element to format with markup.
4625 * @param oRecord {YAHOO.widget.Record} Record instance.
4626 * @param oColumn {YAHOO.widget.Column} Column instance.
4627 * @param oData {Object} Data value for the cell, or null.
4630 YAHOO.widget.DataTable.formatNumber = function(el, oRecord, oColumn, oData) {
4631 if(YAHOO.lang.isNumber(oData)) {
4632 el.innerHTML = oData;
4635 el.innerHTML = YAHOO.lang.isValue(oData) ? oData : "";
4640 * Formats INPUT TYPE=RADIO elements.
4642 * @method DataTable.formatRadio
4643 * @param el {HTMLElement} The element to format with markup.
4644 * @param oRecord {YAHOO.widget.Record} Record instance.
4645 * @param oColumn {YAHOO.widget.Column} Column instance.
4646 * @param oData {Object} (Optional) Data value for the cell.
4649 YAHOO.widget.DataTable.formatRadio = function(el, oRecord, oColumn, oData) {
4650 var bChecked = oData;
4651 bChecked = (bChecked) ? " checked" : "";
4652 el.innerHTML = "<input type=\"radio\"" + bChecked +
4653 " name=\"" + oColumn.getId() + "-radio\"" +
4654 " class=\"" + YAHOO.widget.DataTable.CLASS_CHECKBOX + "\">";
4658 * Formats text strings.
4660 * @method DataTable.formatText
4661 * @param el {HTMLElement} The element to format with markup.
4662 * @param oRecord {YAHOO.widget.Record} Record instance.
4663 * @param oColumn {YAHOO.widget.Column} Column instance.
4664 * @param oData {Object} (Optional) Data value for the cell.
4667 YAHOO.widget.DataTable.formatText = function(el, oRecord, oColumn, oData) {
4668 var value = (YAHOO.lang.isValue(oRecord.getData(oColumn.key))) ?
4669 oRecord.getData(oColumn.key) : "";
4670 //TODO: move to util function
4671 el.innerHTML = value.toString().replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
4675 * Formats TEXTAREA elements.
4677 * @method DataTable.formatTextarea
4678 * @param el {HTMLElement} The element to format with markup.
4679 * @param oRecord {YAHOO.widget.Record} Record instance.
4680 * @param oColumn {YAHOO.widget.Column} Column instance.
4681 * @param oData {Object} (Optional) Data value for the cell.
4684 YAHOO.widget.DataTable.formatTextarea = function(el, oRecord, oColumn, oData) {
4685 var value = (YAHOO.lang.isValue(oRecord.getData(oColumn.key))) ?
4686 oRecord.getData(oColumn.key) : "";
4687 var markup = "<textarea>" + value + "</textarea>";
4688 el.innerHTML = markup;
4692 * Formats INPUT TYPE=TEXT elements.
4694 * @method DataTable.formatTextbox
4695 * @param el {HTMLElement} The element to format with markup.
4696 * @param oRecord {YAHOO.widget.Record} Record instance.
4697 * @param oColumn {YAHOO.widget.Column} Column instance.
4698 * @param oData {Object} (Optional) Data value for the cell.
4701 YAHOO.widget.DataTable.formatTextbox = function(el, oRecord, oColumn, oData) {
4702 var value = (YAHOO.lang.isValue(oRecord.getData(oColumn.key))) ?
4703 oRecord.getData(oColumn.key) : "";
4704 var markup = "<input type=\"text\" value=\"" + value + "\">";
4705 el.innerHTML = markup;
4758 * Updates Paginator values in response to RecordSet changes and/or DOM events.
4759 * Pass in all, a subset, or no values.
4761 * @method updatePaginator
4762 * @param oNewValues {Object} (Optional) Object literal of Paginator values, or
4763 * a subset of Paginator values.
4764 * @param {Object} Object literal of all Paginator values.
4767 YAHOO.widget.DataTable.prototype.updatePaginator = function(oNewValues) {
4769 var oValidPaginator = this.get("paginator");
4770 for(var param in oNewValues) {
4771 if(oValidPaginator.hasOwnProperty(param)) {
4772 oValidPaginator[param] = oNewValues[param];
4776 oValidPaginator.totalRecords = this._oRecordSet.getLength();
4777 oValidPaginator.rowsThisPage = Math.min(oValidPaginator.rowsPerPage, oValidPaginator.totalRecords);
4778 oValidPaginator.totalPages = Math.ceil(oValidPaginator.totalRecords / oValidPaginator.rowsThisPage);
4779 if(isNaN(oValidPaginator.totalPages)) {
4780 oValidPaginator.totalPages = 0;
4783 this.set("paginator", oValidPaginator);
4784 return this.get("paginator");
4788 * Displays given page of a paginated DataTable.
4791 * @param nPage {Number} Which page.
4793 YAHOO.widget.DataTable.prototype.showPage = function(nPage) {
4795 if(!YAHOO.lang.isNumber(nPage) || (nPage < 1) || (nPage > this.get("paginator").totalPages)) {
4798 this.updatePaginator({currentPage:nPage});
4803 * Updates Paginator containers with markup. Override this method to customize pagination UI.
4805 * @method formatPaginators
4807 YAHOO.widget.DataTable.prototype.formatPaginators = function() {
4808 var pag = this.get("paginator");
4810 // For Opera workaround
4811 var dropdownEnabled = false;
4813 // Links are enabled
4814 if(pag.pageLinks > -1) {
4815 for(var i=0; i<pag.links.length; i++) {
4816 this.formatPaginatorLinks(pag.links[i], pag.currentPage, pag.pageLinksStart, pag.pageLinks, pag.totalPages);
4820 // Dropdown is enabled
4821 for(i=0; i<pag.dropdowns.length; i++) {
4822 if(pag.dropdownOptions) {
4823 dropdownEnabled = true;
4824 this.formatPaginatorDropdown(pag.dropdowns[i], pag.dropdownOptions);
4827 pag.dropdowns[i].style.display = "none";
4831 // For Opera artifacting in dropdowns
4832 if(dropdownEnabled && navigator.userAgent.toLowerCase().indexOf("opera") != -1) {
4833 document.body.style += '';
4835 YAHOO.log("Paginators formatted", "info", this.toString());
4839 * Updates Paginator dropdown. If dropdown doesn't exist, the markup is created.
4840 * Sets dropdown elements's "selected" value.
4842 * @method formatPaginatorDropdown
4843 * @param elDropdown {HTMLElement} The SELECT element.
4844 * @param dropdownOptions {Object[]} OPTION values for display in the SELECT element.
4846 YAHOO.widget.DataTable.prototype.formatPaginatorDropdown = function(elDropdown, dropdownOptions) {
4847 if(elDropdown && (elDropdown.ownerDocument == document)) {
4848 // Clear OPTION elements
4849 while (elDropdown.firstChild) {
4850 elDropdown.removeChild(elDropdown.firstChild);
4853 // Create OPTION elements
4854 for(var j=0; j<dropdownOptions.length; j++) {
4855 var dropdownOption = dropdownOptions[j];
4856 var optionEl = document.createElement("option");
4857 optionEl.value = (YAHOO.lang.isValue(dropdownOption.value)) ?
4858 dropdownOption.value : dropdownOption;
4859 optionEl.innerHTML = (YAHOO.lang.isValue(dropdownOption.text)) ?
4860 dropdownOption.text : dropdownOption;
4861 optionEl = elDropdown.appendChild(optionEl);
4864 var options = elDropdown.options;
4865 // Update dropdown's "selected" value
4866 if(options.length) {
4867 for(var i=options.length-1; i>-1; i--) {
4868 if((this.get("paginator").rowsPerPage + "") === options[i].value) {
4869 options[i].selected = true;
4874 // Show the dropdown
4875 elDropdown.style.display = "";
4878 YAHOO.log("Could not update Paginator dropdown " + elDropdown, "error", this.toString());
4882 * Updates Paginator links container with markup.
4884 * @method formatPaginatorLinks
4885 * @param elContainer {HTMLElement} The link container element.
4886 * @param nCurrentPage {Number} Current page.
4887 * @param nPageLinksStart {Number} First page link to display.
4888 * @param nPageLinksLength {Number} How many page links to display.
4889 * @param nTotalPages {Number} Total number of pages.
4891 YAHOO.widget.DataTable.prototype.formatPaginatorLinks = function(elContainer, nCurrentPage, nPageLinksStart, nPageLinksLength, nTotalPages) {
4892 if(elContainer && (elContainer.ownerDocument == document) &&
4893 YAHOO.lang.isNumber(nCurrentPage) && YAHOO.lang.isNumber(nPageLinksStart) &&
4894 YAHOO.lang.isNumber(nTotalPages)) {
4895 // Set up markup for first/last/previous/next
4896 var bIsFirstPage = (nCurrentPage == 1) ? true : false;
4897 var bIsLastPage = (nCurrentPage == nTotalPages) ? true : false;
4898 var sFirstLinkMarkup = (bIsFirstPage) ?
4899 " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
4900 " " + YAHOO.widget.DataTable.CLASS_FIRST + "\"><<</span> " :
4901 " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_FIRST + "\"><<</a> ";
4902 var sPrevLinkMarkup = (bIsFirstPage) ?
4903 " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
4904 " " + YAHOO.widget.DataTable.CLASS_PREVIOUS + "\"><</span> " :
4905 " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_PREVIOUS + "\"><</a> " ;
4906 var sNextLinkMarkup = (bIsLastPage) ?
4907 " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
4908 " " + YAHOO.widget.DataTable.CLASS_NEXT + "\">></span> " :
4909 " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_NEXT + "\">></a> " ;
4910 var sLastLinkMarkup = (bIsLastPage) ?
4911 " <span class=\"" + YAHOO.widget.DataTable.CLASS_DISABLED +
4912 " " + YAHOO.widget.DataTable.CLASS_LAST + "\">>></span> " :
4913 " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_LAST + "\">>></a> ";
4915 // Start with first and previous
4916 var sMarkup = sFirstLinkMarkup + sPrevLinkMarkup;
4918 // Ok to show all links
4919 var nMaxLinks = nTotalPages;
4921 var nLastLink = nTotalPages;
4923 if(nPageLinksLength > 0) {
4924 // Calculate how many links to show
4925 nMaxLinks = (nPageLinksStart+nPageLinksLength < nTotalPages) ?
4926 nPageLinksStart+nPageLinksLength-1 : nTotalPages;
4928 // Try to keep the current page in the middle
4929 nFirstLink = (nCurrentPage - Math.floor(nMaxLinks/2) > 0) ? nCurrentPage - Math.floor(nMaxLinks/2) : 1;
4930 nLastLink = (nCurrentPage + Math.floor(nMaxLinks/2) <= nTotalPages) ? nCurrentPage + Math.floor(nMaxLinks/2) : nTotalPages;
4932 // Keep the last link in range
4933 if(nFirstLink === 1) {
4934 nLastLink = nMaxLinks;
4936 // Keep the first link in range
4937 else if(nLastLink === nTotalPages) {
4938 nFirstLink = nTotalPages - nMaxLinks + 1;
4941 // An even number of links can get funky
4942 if(nLastLink - nFirstLink === nMaxLinks) {
4947 // Generate markup for each page
4948 for(var i=nFirstLink; i<=nLastLink; i++) {
4949 if(i != nCurrentPage) {
4950 sMarkup += " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_PAGE + "\">" + i + "</a> ";
4953 sMarkup += " <span class=\"" + YAHOO.widget.DataTable.CLASS_SELECTED + "\">" + i + "</span>";
4956 sMarkup += sNextLinkMarkup + sLastLinkMarkup;
4957 elContainer.innerHTML = sMarkup;
4960 YAHOO.log("Could not format Paginator links", "error", this.toString());
5011 // SELECTION/HIGHLIGHTING
5014 * ID string of last highlighted cell element
5016 * @property _sLastHighlightedCellId
5020 YAHOO.widget.DataTable.prototype._sLastHighlightedCellId = null;
5023 * ID string of last highlighted row element
5025 * @property _sLastHighlightedRowId
5029 YAHOO.widget.DataTable.prototype._sLastHighlightedRowId = null;
5032 * Array of selections: {recordId:nRecordId, cellIndex:nCellIndex}
5034 * @property _aSelections
5038 YAHOO.widget.DataTable.prototype._aSelections = null;
5041 * ID string of last selected element
5043 * @property _sLastSelectedId
5047 YAHOO.widget.DataTable.prototype._sLastSelectedId = null;
5050 * ID string of the selection anchor element.
5052 * @property _sSelectionAnchorId
5056 YAHOO.widget.DataTable.prototype._sSelectionAnchorId = null;
5059 * Convenience method to remove the class YAHOO.widget.DataTable.CLASS_SELECTED
5060 * from all TR elements on the page.
5062 * @method _unselectAllTrEls
5065 YAHOO.widget.DataTable.prototype._unselectAllTrEls = function() {
5066 var selectedRows = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"tr",this._elTbody);
5067 YAHOO.util.Dom.removeClass(selectedRows, YAHOO.widget.DataTable.CLASS_SELECTED);
5071 * Returns array of selected TR elements on the page.
5073 * @method getSelectedTrEls
5074 * @return {HTMLElement[]} Array of selected TR elements.
5076 YAHOO.widget.DataTable.prototype.getSelectedTrEls = function() {
5077 return YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"tr",this._elTbody);
5081 * Sets given row to the selected state.
5084 * @param row {HTMLElement | String} HTML element reference or ID.
5086 YAHOO.widget.DataTable.prototype.selectRow = function(row) {
5088 var elRow = this.getTrEl(row);
5090 var oRecord = this.getRecord(elRow);
5093 var tracker = this._aSelections || [];
5094 var nRecordId = oRecord.getId();
5095 // Remove if already there
5097 // Use Array.indexOf if available...
5098 if(tracker.indexOf && (tracker.indexOf(nRecordId) > -1)) {
5099 tracker.splice(tracker.indexOf(nRecordId),1);
5101 // ...or do it the old-fashioned way
5103 for(var j=0; j<tracker.length; j++) {
5104 if(tracker[j] === nRecordId){
5105 tracker.splice(j,1);
5110 tracker.push(nRecordId);
5113 this._sLastSelectedId = elRow.id;
5114 if(!this._sSelectionAnchorId) {
5115 this._sSelectionAnchorId = elRow.id;
5117 this._aSelections = tracker;
5120 YAHOO.util.Dom.addClass(elRow, YAHOO.widget.DataTable.CLASS_SELECTED);
5122 this.fireEvent("rowSelectEvent", {record:oRecord, el:elRow});
5123 YAHOO.log("Selected " + elRow, "info", this.toString());
5128 YAHOO.log("Could not select " + row, "warn", this.toString());
5130 // Backward compatibility
5131 YAHOO.widget.DataTable.prototype.select = function(els) {
5132 YAHOO.log("The method select() has been deprecated" +
5133 " in favor of selectRow()", "warn", this.toString());
5134 if(!YAHOO.lang.isArray(els)) {
5137 for(var i=0; i<els.length; i++) {
5138 this.selectRow(els[i]);
5143 * Sets given row to the unselected state.
5145 * @method unselectRow
5146 * @param row {HTMLElement | String} HTML TR element reference or ID.
5148 YAHOO.widget.DataTable.prototype.unselectRow = function(row) {
5150 var elRow = this.getTrEl(row);
5152 var oRecord = this.getRecord(elRow);
5155 var tracker = this._aSelections || [];
5156 var nRecordId = oRecord.getId();
5161 // Use Array.indexOf if available...
5162 if(tracker.indexOf && (tracker.indexOf(nRecordId) > -1)) {
5163 tracker.splice(tracker.indexOf(nRecordId),1);
5166 // ...or do it the old-fashioned way
5168 for(var j=0; j<tracker.length; j++) {
5169 if(tracker[j] === nRecordId){
5170 tracker.splice(j,1);
5178 this._aSelections = tracker;
5181 YAHOO.util.Dom.removeClass(elRow, YAHOO.widget.DataTable.CLASS_SELECTED);
5183 this.fireEvent("rowUnselectEvent", {record:oRecord, el:elRow});
5184 YAHOO.log("Unselected " + elRow, "info", this.toString());
5190 YAHOO.log("Could not unselect row " + row, "warn", this.toString());
5194 * Clears out all row selections.
5196 * @method unselectAllRows
5198 YAHOO.widget.DataTable.prototype.unselectAllRows = function() {
5199 // Remove from tracker
5200 var tracker = this._aSelections || [];
5201 for(var j=0; j<tracker.length; j++) {
5202 if(YAHOO.lang.isNumber(tracker[j])){
5203 tracker.splice(j,1);
5208 this._aSelections = tracker;
5211 this._unselectAllTrEls();
5213 //TODO: send an array of [{el:el,record:record}]
5214 //TODO: or convert this to an unselectRows method
5215 //TODO: that takes an array of rows or unselects all if none given
5216 this.fireEvent("unselectAllRowsEvent");
5217 YAHOO.log("Unselected all rows", "info", this.toString());
5221 * Convenience method to remove the class YAHOO.widget.DataTable.CLASS_SELECTED
5222 * from all TD elements in the internal tracker.
5224 * @method _unselectAllTdEls
5227 YAHOO.widget.DataTable.prototype._unselectAllTdEls = function() {
5228 var selectedCells = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"td",this._elTbody);
5229 YAHOO.util.Dom.removeClass(selectedCells, YAHOO.widget.DataTable.CLASS_SELECTED);
5233 * Returns array of selected TD elements on the page.
5235 * @method getSelectedTdEls
5236 * @return {HTMLElement[]} Array of selected TD elements.
5238 YAHOO.widget.DataTable.prototype.getSelectedTdEls = function() {
5239 return YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_SELECTED,"td",this._elTbody);
5243 * Sets given cell to the selected state.
5245 * @method selectCell
5246 * @param cell {HTMLElement | String} DOM element reference or ID string
5247 * to DataTable page element or RecordSet index.
5249 YAHOO.widget.DataTable.prototype.selectCell = function(cell) {
5250 var elCell = this.getTdEl(cell);
5253 var oRecord = this.getRecord(elCell);
5254 var nColumnId = elCell.yuiColumnId;
5256 if(oRecord && YAHOO.lang.isNumber(nColumnId)) {
5258 var tracker = this._aSelections || [];
5259 var nRecordId = oRecord.getId();
5262 for(var j=0; j<tracker.length; j++) {
5263 if((tracker[j].recordId === nRecordId) && (tracker[j].columnId === nColumnId)){
5264 tracker.splice(j,1);
5269 tracker.push({recordId:nRecordId, columnId:nColumnId});
5272 this._aSelections = tracker;
5273 this._sLastSelectedId = elCell.id;
5274 if(!this._sSelectionAnchorId) {
5275 this._sSelectionAnchorId = elCell.id;
5279 YAHOO.util.Dom.addClass(elCell, YAHOO.widget.DataTable.CLASS_SELECTED);
5281 this.fireEvent("cellSelectEvent", {record:oRecord,
5282 key: this._oColumnSet.getColumn(nColumnId).key, el:elCell});
5283 YAHOO.log("Selected " + elCell, "info", this.toString());
5287 YAHOO.log("Could not select " + cell, "warn", this.toString());
5291 * Sets given cell to the unselected state.
5293 * @method unselectCell
5294 * @param cell {HTMLElement | String} DOM element reference or ID string
5295 * to DataTable page element or RecordSet index.
5297 YAHOO.widget.DataTable.prototype.unselectCell = function(cell) {
5298 var elCell = this.getTdEl(cell);
5301 var oRecord = this.getRecord(elCell);
5302 var nColumnId = elCell.yuiColumnId;
5304 if(oRecord && YAHOO.lang.isNumber(nColumnId)) {
5306 var tracker = this._aSelections || [];
5307 var id = oRecord.getId();
5310 for(var j=0; j<tracker.length; j++) {
5311 if((tracker[j].recordId === id) && (tracker[j].columnId === nColumnId)){
5312 // Remove from tracker
5313 tracker.splice(j,1);
5316 this._aSelections = tracker;
5319 YAHOO.util.Dom.removeClass(elCell, YAHOO.widget.DataTable.CLASS_SELECTED);
5321 this.fireEvent("cellUnselectEvent", {record:oRecord,
5322 key:this._oColumnSet.getColumn(nColumnId).key, el:elCell});
5323 YAHOO.log("Unselected " + elCell, "info", this.toString());
5330 YAHOO.log("Could not unselect " + cell, "warn", this.toString());
5334 * Clears out all cell selections.
5336 * @method unselectAllCells
5338 YAHOO.widget.DataTable.prototype.unselectAllCells= function() {
5339 // Remove from tracker
5340 var tracker = this._aSelections || [];
5341 for(var j=0; j<tracker.length; j++) {
5342 if(tracker[j].constructor == Object){
5343 tracker.splice(j,1);
5348 this._aSelections = tracker;
5351 this._unselectAllTdEls();
5354 //TODO: or fire individual cellUnselectEvent
5355 this.fireEvent("unselectAllCellsEvent");
5356 YAHOO.log("Unselected all cells", "info", this.toString());
5360 * Returns true if given TR or TD element is select, false otherwise.
5362 * @method isSelected
5363 * @param el {HTMLElement} HTML element reference or ID of a TR or TD.
5364 * @return {Boolean} True if element is selected.
5366 YAHOO.widget.DataTable.prototype.isSelected = function(el) {
5367 return YAHOO.util.Dom.hasClass(el,YAHOO.widget.DataTable.CLASS_SELECTED);
5371 * Returns selected rows as an array of Record IDs.
5373 * @method getSelectedRows
5374 * @return {HTMLElement[]} Array of selected rows by Record ID.
5376 YAHOO.widget.DataTable.prototype.getSelectedRows = function() {
5377 var aSelectedRows = [];
5378 var tracker = this._aSelections || [];
5379 for(var j=0; j<tracker.length; j++) {
5380 if(YAHOO.lang.isNumber(tracker[j])){
5381 aSelectedRows.push(tracker[j]);
5384 return aSelectedRows;
5388 * Returns selected cells as an array of object literals:
5389 * {recordId:nRecordID, columnId:nColumnId}.
5391 * @method getSelectedCells
5392 * @return {HTMLElement[]} Array of selected cells by Record and Column IDs.
5394 YAHOO.widget.DataTable.prototype.getSelectedCells = function() {
5395 var aSelectedCells = [];
5396 var tracker = this._aSelections || [];
5397 for(var j=0; j<tracker.length; j++) {
5398 if(tracker[j] && (tracker[j].constructor == Object)){
5399 aSelectedCells.push({recordId:tracker[j].recordId, columnId:tracker[j].columnId});
5402 return aSelectedCells;
5406 * Assigns the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED to the given row.
5408 * @method highlightRow
5409 * @param row {HTMLElement | String} DOM element reference or ID string.
5411 YAHOO.widget.DataTable.prototype.highlightRow = function(row) {
5412 var elRow = this.getTrEl(row);
5415 // Make sure previous row is unhighlighted
5416 if(this._sLastHighlightedRowId) {
5417 YAHOO.util.Dom.removeClass(this._sLastHighlightedRowId,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
5419 var oRecord = this.getRecord(elRow);
5420 YAHOO.util.Dom.addClass(elRow,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
5421 this._sLastHighlightedRowId = elRow.id;
5422 this.fireEvent("rowHighlightEvent", {record:oRecord, el:elRow});
5423 YAHOO.log("Highlighted " + elRow, "info", this.toString());
5426 YAHOO.log("Could not highlight " + row, "warn", this.toString());
5430 * Removes the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED from the given row.
5432 * @method unhighlightRow
5433 * @param row {HTMLElement | String} DOM element reference or ID string.
5435 YAHOO.widget.DataTable.prototype.unhighlightRow = function(row) {
5436 var elRow = this.getTrEl(row);
5439 var oRecord = this.getRecord(elRow);
5440 YAHOO.util.Dom.removeClass(elRow,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
5441 this.fireEvent("rowUnhighlightEvent", {record:oRecord, el:elRow});
5442 YAHOO.log("Unhighlighted " + elRow, "info", this.toString());
5445 YAHOO.log("Could not unhighlight " + row, "warn", this.toString());
5449 * Assigns the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED to the given cell.
5451 * @method highlightCell
5452 * @param cell {HTMLElement | String} DOM element reference or ID string.
5454 YAHOO.widget.DataTable.prototype.highlightCell = function(cell) {
5455 var elCell = this.getTdEl(cell);
5458 // Make sure previous cell is unhighlighted
5459 if(this._sLastHighlightedCellId) {
5460 YAHOO.util.Dom.removeClass(this._sLastHighlightedCellId,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
5463 var oRecord = this.getRecord(elCell);
5464 YAHOO.util.Dom.addClass(elCell,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
5465 this._sLastHighlightedCellId = elCell.id;
5466 this.fireEvent("cellHighlightEvent", {record:oRecord,
5467 key:this._oColumnSet.getColumn(elCell.yuiColumnId).key, el:elCell});
5468 YAHOO.log("Highlighted " + elCell, "info", this.toString());
5471 YAHOO.log("Could not highlight " + cell, "warn", this.toString());
5475 * Removes the class YAHOO.widget.DataTable.CLASS_HIGHLIGHTED from the given cell.
5477 * @method unhighlightCell
5478 * @param cell {HTMLElement | String} DOM element reference or ID string.
5480 YAHOO.widget.DataTable.prototype.unhighlightCell = function(cell) {
5481 var elCell = this.getTdEl(cell);
5484 var oRecord = this.getRecord(elCell);
5485 YAHOO.util.Dom.removeClass(elCell,YAHOO.widget.DataTable.CLASS_HIGHLIGHTED);
5486 this.fireEvent("cellUnhighlightEvent", {record:oRecord,
5487 key:this._oColumnSet.getColumn(elCell.yuiColumnId).key, el:elCell});
5488 YAHOO.log("Unhighlighted " + elCell, "info", this.toString());
5491 YAHOO.log("Could not unhighlight " + cell, "warn", this.toString());
5540 /*TODO: for TAB handling
5541 * Shows Cell Editor for next cell.
5543 * @method editNextCell
5544 * @param elCell {HTMLElement} Cell element from which to edit next cell.
5546 //YAHOO.widget.DataTable.prototype.editNextCell = function(elCell) {
5550 * Shows Cell Editor for given cell.
5552 * @method showCellEditor
5553 * @param elCell {HTMLElement | String} Cell element to edit.
5554 * @param oRecord {YAHOO.widget.Record} (Optional) Record instance.
5555 * @param oColumn {YAHOO.widget.Column} (Optional) Column instance.
5557 YAHOO.widget.DataTable.prototype.showCellEditor = function(elCell, oRecord, oColumn) {
5558 elCell = YAHOO.util.Dom.get(elCell);
5560 if(elCell && (elCell.ownerDocument === document)) {
5561 if(!oRecord || !(oRecord instanceof YAHOO.widget.Record)) {
5562 oRecord = this.getRecord(elCell);
5564 if(!oColumn || !(oColumn instanceof YAHOO.widget.Column)) {
5565 oColumn = this.getColumn(elCell);
5567 if(oRecord && oColumn) {
5568 var oCellEditor = this._oCellEditor;
5570 // Clear previous Editor
5571 if(oCellEditor.isActive) {
5572 this.cancelCellEditor();
5575 // Editor not defined
5576 if(!oColumn.editor) {
5580 // Update Editor values
5581 oCellEditor.cell = elCell;
5582 oCellEditor.record = oRecord;
5583 oCellEditor.column = oColumn;
5584 oCellEditor.validator = (oColumn.editorOptions &&
5585 YAHOO.lang.isFunction(oColumn.editorOptions.validator)) ?
5586 oColumn.editorOptions.validator : null;
5587 oCellEditor.value = oRecord.getData(oColumn.key);
5590 var elContainer = oCellEditor.container;
5591 var x = YAHOO.util.Dom.getX(elCell);
5592 var y = YAHOO.util.Dom.getY(elCell);
5594 // SF doesn't get xy for cells in scrolling table
5595 // when tbody display is set to block
5596 if(isNaN(x) || isNaN(y)) {
5597 x = elCell.offsetLeft + // cell pos relative to table
5598 YAHOO.util.Dom.getX(this._elTable) - // plus table pos relative to document
5599 this._elTbody.scrollLeft; // minus tbody scroll
5600 y = elCell.offsetTop + // cell pos relative to table
5601 YAHOO.util.Dom.getY(this._elTable) - // plus table pos relative to document
5602 this._elTbody.scrollTop + // minus tbody scroll
5603 this._elThead.offsetHeight; // account for fixed headers
5606 elContainer.style.left = x + "px";
5607 elContainer.style.top = y + "px";
5610 elContainer.style.display = "";
5612 // Render Editor markup
5614 if(YAHOO.lang.isString(oColumn.editor)) {
5615 switch(oColumn.editor) {
5617 fnEditor = YAHOO.widget.DataTable.editCheckbox;
5620 fnEditor = YAHOO.widget.DataTable.editDate;
5623 fnEditor = YAHOO.widget.DataTable.editDropdown;
5626 fnEditor = YAHOO.widget.DataTable.editRadio;
5629 fnEditor = YAHOO.widget.DataTable.editTextarea;
5632 fnEditor = YAHOO.widget.DataTable.editTextbox;
5638 else if(YAHOO.lang.isFunction(oColumn.editor)) {
5639 fnEditor = oColumn.editor;
5643 // Create DOM input elements
5644 fnEditor(this._oCellEditor, this);
5646 // Show Save/Cancel buttons
5647 if(!oColumn.editorOptions || !oColumn.editorOptions.disableBtns) {
5648 this.showCellEditorBtns(elContainer);
5651 // Hook to customize the UI
5652 this.doBeforeShowCellEditor(this._oCellEditor);
5654 oCellEditor.isActive = true;
5656 //TODO: verify which args to pass
5657 this.fireEvent("editorShowEvent", {editor:oCellEditor});
5658 YAHOO.log("Cell Editor shown for " + elCell, "info", this.toString());
5663 YAHOO.log("Could not show Cell Editor for " + elCell, "warn", this.toString());
5667 * Overridable abstract method to customize Cell Editor UI.
5669 * @method doBeforeShowCellEditor
5670 * @param oCellEditor {Object} Cell Editor object literal.
5672 YAHOO.widget.DataTable.prototype.doBeforeShowCellEditor = function(oCellEditor) {
5676 * Adds Save/Cancel buttons to Cell Editor.
5678 * @method showCellEditorBtns
5679 * @param elContainer {HTMLElement} Cell Editor container.
5681 YAHOO.widget.DataTable.prototype.showCellEditorBtns = function(elContainer) {
5683 var elBtnsDiv = elContainer.appendChild(document.createElement("div"));
5684 YAHOO.util.Dom.addClass(elBtnsDiv, YAHOO.widget.DataTable.CLASS_BUTTON);
5687 var elSaveBtn = elBtnsDiv.appendChild(document.createElement("button"));
5688 YAHOO.util.Dom.addClass(elSaveBtn, YAHOO.widget.DataTable.CLASS_DEFAULT);
5689 elSaveBtn.innerHTML = "OK";
5690 YAHOO.util.Event.addListener(elSaveBtn, "click", this.saveCellEditor, this, true);
5693 var elCancelBtn = elBtnsDiv.appendChild(document.createElement("button"));
5694 elCancelBtn.innerHTML = "Cancel";
5695 YAHOO.util.Event.addListener(elCancelBtn, "click", this.cancelCellEditor, this, true);
5699 * Clears Cell Editor of all state and UI.
5701 * @method resetCellEditor
5704 YAHOO.widget.DataTable.prototype.resetCellEditor = function() {
5705 var elContainer = this._oCellEditor.container;
5706 elContainer.style.display = "none";
5707 YAHOO.util.Event.purgeElement(elContainer, true);
5708 elContainer.innerHTML = "";
5709 this._oCellEditor.value = null;
5710 this._oCellEditor.isActive = false;
5714 * Saves Cell Editor input to Record.
5716 * @method saveCellEditor
5718 YAHOO.widget.DataTable.prototype.saveCellEditor = function() {
5719 //TODO: Copy the editor's values to pass to the event
5720 if(this._oCellEditor.isActive) {
5721 var newData = this._oCellEditor.value;
5722 var oldData = this._oCellEditor.record.getData(this._oCellEditor.column.key);
5724 // Validate input data
5725 if(this._oCellEditor.validator) {
5726 this._oCellEditor.value = this._oCellEditor.validator.call(this, newData, oldData);
5727 if(this._oCellEditor.value === null ) {
5728 this.resetCellEditor();
5729 this.fireEvent("editorRevertEvent",
5730 {editor:this._oCellEditor, oldData:oldData, newData:newData});
5731 YAHOO.log("Could not save Cell Editor input due to invalid data " +
5732 YAHOO.lang.dump(newData), "warn", this.toString());
5737 // Update the Record
5738 this._oRecordSet.updateKey(this._oCellEditor.record, this._oCellEditor.column.key, this._oCellEditor.value);
5741 this.formatCell(this._oCellEditor.cell);
5743 // Clear out the Cell Editor
5744 this.resetCellEditor();
5746 this.fireEvent("editorSaveEvent",
5747 {editor:this._oCellEditor, oldData:oldData, newData:newData});
5748 YAHOO.log("Cell Editor input saved", "info", this.toString());
5751 YAHOO.log("Cell Editor not active to save input", "warn", this.toString());
5756 * Cancels Cell Editor.
5758 * @method cancelCellEditor
5760 YAHOO.widget.DataTable.prototype.cancelCellEditor = function() {
5761 if(this._oCellEditor.isActive) {
5762 this.resetCellEditor();
5763 //TODO: preserve values for the event?
5764 this.fireEvent("editorCancelEvent", {editor:this._oCellEditor});
5765 YAHOO.log("Cell Editor input canceled", "info", this.toString());
5768 YAHOO.log("Cell Editor not active to cancel input", "warn", this.toString());
5773 * Enables CHECKBOX Editor.
5775 * @method editCheckbox
5777 //YAHOO.widget.DataTable.editCheckbox = function(elContainer, oRecord, oColumn, oEditor, oSelf) {
5778 YAHOO.widget.DataTable.editCheckbox = function(oEditor, oSelf) {
5779 var elCell = oEditor.cell;
5780 var oRecord = oEditor.record;
5781 var oColumn = oEditor.column;
5782 var elContainer = oEditor.container;
5783 var aCheckedValues = oRecord.getData(oColumn.key);
5784 if(!YAHOO.lang.isArray(aCheckedValues)) {
5785 aCheckedValues = [aCheckedValues];
5789 if(oColumn.editorOptions && YAHOO.lang.isArray(oColumn.editorOptions.checkboxOptions)) {
5790 var checkboxOptions = oColumn.editorOptions.checkboxOptions;
5791 var checkboxValue, checkboxId, elLabel, j, k;
5792 // First create the checkbox buttons in an IE-friendly way
5793 for(j=0; j<checkboxOptions.length; j++) {
5794 checkboxValue = YAHOO.lang.isValue(checkboxOptions[j].label) ?
5795 checkboxOptions[j].label : checkboxOptions[j];
5796 checkboxId = oSelf.id + "-editor-checkbox" + j;
5797 elContainer.innerHTML += "<input type=\"checkbox\"" +
5798 " name=\"" + oSelf.id + "-editor-checkbox\"" +
5799 " value=\"" + checkboxValue + "\"" +
5800 " id=\"" + checkboxId + "\">";
5801 // Then create the labels in an IE-friendly way
5802 elLabel = elContainer.appendChild(document.createElement("label"));
5803 elLabel.htmlFor = checkboxId;
5804 elLabel.innerHTML = checkboxValue;
5806 var aCheckboxEls = [];
5808 // Loop through checkboxes to check them
5809 for(j=0; j<checkboxOptions.length; j++) {
5810 checkboxEl = YAHOO.util.Dom.get(oSelf.id + "-editor-checkbox" + j);
5811 aCheckboxEls.push(checkboxEl);
5812 for(k=0; k<aCheckedValues.length; k++) {
5813 if(checkboxEl.value === aCheckedValues[k]) {
5814 checkboxEl.checked = true;
5817 // Focus the first checkbox
5819 oSelf._focusEl(checkboxEl);
5822 // Loop through checkboxes to assign click handlers
5823 for(j=0; j<checkboxOptions.length; j++) {
5824 checkboxEl = YAHOO.util.Dom.get(oSelf.id + "-editor-checkbox" + j);
5825 YAHOO.util.Event.addListener(checkboxEl, "click", function(){
5826 var aNewValues = [];
5827 for(var m=0; m<aCheckboxEls.length; m++) {
5828 if(aCheckboxEls[m].checked) {
5829 aNewValues.push(aCheckboxEls[m].value);
5832 oSelf._oCellEditor.value = aNewValues;
5833 oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
5840 * Enables Date Editor.
5844 YAHOO.widget.DataTable.editDate = function(oEditor, oSelf) {
5845 var elCell = oEditor.cell;
5846 var oRecord = oEditor.record;
5847 var oColumn = oEditor.column;
5848 var elContainer = oEditor.container;
5849 var value = oRecord.getData(oColumn.key);
5852 if(YAHOO.widget.Calendar) {
5853 var selectedValue = (value.getMonth()+1)+"/"+value.getDate()+"/"+value.getFullYear();
5854 var calContainer = elContainer.appendChild(document.createElement("div"));
5855 calContainer.id = "yui-dt-" + oSelf._nIndex + "-col" + oColumn.getKeyIndex() + "-dateContainer";
5857 new YAHOO.widget.Calendar("yui-dt-" + oSelf._nIndex + "-col" + oColumn.getKeyIndex() + "-date",
5859 {selected:selectedValue, pagedate:value});
5861 calContainer.style.cssFloat = "none";
5863 //var calFloatClearer = elContainer.appendChild(document.createElement("br"));
5864 //calFloatClearer.style.clear = "both";
5866 calendar.selectEvent.subscribe(function(type, args, obj) {
5867 oSelf._oCellEditor.value = new Date(args[0][0][0], args[0][0][1]-1, args[0][0][2]);
5869 oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
5877 * Enables SELECT Editor.
5879 * @method editDropdown
5881 YAHOO.widget.DataTable.editDropdown = function(oEditor, oSelf) {
5882 var elCell = oEditor.cell;
5883 var oRecord = oEditor.record;
5884 var oColumn = oEditor.column;
5885 var elContainer = oEditor.container;
5886 var value = oRecord.getData(oColumn.key);
5889 var elDropdown = elContainer.appendChild(document.createElement("select"));
5890 var dropdownOptions = (oColumn.editorOptions && YAHOO.lang.isArray(oColumn.editorOptions.dropdownOptions)) ?
5891 oColumn.editorOptions.dropdownOptions : [];
5892 for(var j=0; j<dropdownOptions.length; j++) {
5893 var dropdownOption = dropdownOptions[j];
5894 var elOption = document.createElement("option");
5895 elOption.value = (YAHOO.lang.isValue(dropdownOption.value)) ?
5896 dropdownOption.value : dropdownOption;
5897 elOption.innerHTML = (YAHOO.lang.isValue(dropdownOption.text)) ?
5898 dropdownOption.text : dropdownOption;
5899 elOption = elDropdown.appendChild(elOption);
5900 if(value === elDropdown.options[j].value) {
5901 elDropdown.options[j].selected = true;
5905 // Set up a listener on each check box to track the input value
5906 YAHOO.util.Event.addListener(elDropdown, "change",
5908 oSelf._oCellEditor.value = elDropdown[elDropdown.selectedIndex].value;
5909 oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
5912 // Focus the dropdown
5913 oSelf._focusEl(elDropdown);
5917 * Enables INPUT TYPE=RADIO Editor.
5921 YAHOO.widget.DataTable.editRadio = function(oEditor, oSelf) {
5922 var elCell = oEditor.cell;
5923 var oRecord = oEditor.record;
5924 var oColumn = oEditor.column;
5925 var elContainer = oEditor.container;
5926 var value = oRecord.getData(oColumn.key);
5929 if(oColumn.editorOptions && YAHOO.lang.isArray(oColumn.editorOptions.radioOptions)) {
5930 var radioOptions = oColumn.editorOptions.radioOptions;
5931 var radioValue, radioId, elLabel, j;
5932 // First create the radio buttons in an IE-friendly way
5933 for(j=0; j<radioOptions.length; j++) {
5934 radioValue = YAHOO.lang.isValue(radioOptions[j].label) ?
5935 radioOptions[j].label : radioOptions[j];
5936 radioId = oSelf.id + "-editor-radio" + j;
5937 elContainer.innerHTML += "<input type=\"radio\"" +
5938 " name=\"" + oSelf.id + "-editor-radio\"" +
5939 " value=\"" + radioValue + "\"" +
5940 " id=\"" + radioId + "\">";
5941 // Then create the labels in an IE-friendly way
5942 elLabel = elContainer.appendChild(document.createElement("label"));
5943 elLabel.htmlFor = radioId;
5944 elLabel.innerHTML = radioValue;
5946 // Then check one, and assign click handlers
5947 for(j=0; j<radioOptions.length; j++) {
5948 var radioEl = YAHOO.util.Dom.get(oSelf.id + "-editor-radio" + j);
5949 if(value === radioEl.value) {
5950 radioEl.checked = true;
5951 oSelf._focusEl(radioEl);
5953 YAHOO.util.Event.addListener(radioEl, "click",
5955 oSelf._oCellEditor.value = this.value;
5956 oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
5963 * Enables TEXTAREA Editor.
5965 * @method editTextarea
5967 YAHOO.widget.DataTable.editTextarea = function(oEditor, oSelf) {
5968 var elCell = oEditor.cell;
5969 var oRecord = oEditor.record;
5970 var oColumn = oEditor.column;
5971 var elContainer = oEditor.container;
5972 var value = oRecord.getData(oColumn.key);
5975 var elTextarea = elContainer.appendChild(document.createElement("textarea"));
5976 elTextarea.style.width = elCell.offsetWidth + "px"; //(parseInt(elCell.offsetWidth,10)) + "px";
5977 elTextarea.style.height = "3em"; //(parseInt(elCell.offsetHeight,10)) + "px";
5978 elTextarea.value = YAHOO.lang.isValue(value) ? value : "";
5980 // Set up a listener on each check box to track the input value
5981 YAHOO.util.Event.addListener(elTextarea, "keyup", function(){
5982 //TODO: set on a timeout
5983 oSelf._oCellEditor.value = elTextarea.value;
5984 oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
5989 elTextarea.select();
5993 * Enables INPUT TYPE=TEXT Editor.
5995 * @method editTextbox
5997 YAHOO.widget.DataTable.editTextbox = function(oEditor, oSelf) {
5998 var elCell = oEditor.cell;
5999 var oRecord = oEditor.record;
6000 var oColumn = oEditor.column;
6001 var elContainer = oEditor.container;
6002 var value = YAHOO.lang.isValue(oRecord.getData(oColumn.key)) ? oRecord.getData(oColumn.key) : "";
6005 var elTextbox = elContainer.appendChild(document.createElement("input"));
6006 elTextbox.type = "text";
6007 elTextbox.style.width = elCell.offsetWidth + "px"; //(parseInt(elCell.offsetWidth,10)) + "px";
6008 //elTextbox.style.height = "1em"; //(parseInt(elCell.offsetHeight,10)) + "px";
6009 elTextbox.value = value;
6011 // Set up a listener on each textbox to track the input value
6012 YAHOO.util.Event.addListener(elTextbox, "keyup", function(){
6013 //TODO: set on a timeout
6014 oSelf._oCellEditor.value = elTextbox.value;
6015 oSelf.fireEvent("editorUpdateEvent",{editor:oSelf._oCellEditor});
6024 * Validates Editor input value to type Number, doing type conversion as
6025 * necessary. A valid Number value is return, else the previous value is returned
6026 * if input value does not validate.
6029 * @method validateNumber
6032 YAHOO.widget.DataTable.validateNumber = function(oData) {
6034 var number = oData * 1;
6037 if(YAHOO.lang.isNumber(number)) {
6041 YAHOO.log("Could not validate data " + YAHOO.lang.dump(oData) + " to type Number", "warn", this.toString());
6086 * Overridable method gives implementers a hook to access data before
6087 * it gets added to RecordSet and rendered to the TBODY.
6089 * @method doBeforeLoadData
6090 * @param sRequest {String} Original request.
6091 * @param oResponse {Object} Response object.
6092 * @return {Boolean} Return true to continue loading data into RecordSet and
6093 * updating DataTable with new Records, false to cancel.
6095 YAHOO.widget.DataTable.prototype.doBeforeLoadData = function(sRequest, oResponse) {
6161 /////////////////////////////////////////////////////////////////////////////
6163 // Public Custom Event Handlers
6165 /////////////////////////////////////////////////////////////////////////////
6168 * Overridable custom event handler to sort Column.
6170 * @method onEventSortColumn
6171 * @param oArgs.event {HTMLEvent} Event object.
6172 * @param oArgs.target {HTMLElement} Target element.
6174 YAHOO.widget.DataTable.prototype.onEventSortColumn = function(oArgs) {
6175 //TODO: support nested header column sorting
6176 var evt = oArgs.event;
6177 var target = oArgs.target;
6178 YAHOO.util.Event.stopEvent(evt);
6180 var el = this.getThEl(target) || this.getTdEl(target);
6181 if(el && YAHOO.lang.isNumber(el.yuiColumnId)) {
6182 this.sortColumn(this._oColumnSet.getColumn(el.yuiColumnId));
6185 YAHOO.log("Could not sort column " + target, "warn", this.toString());
6190 * Overridable custom event handler to manage selection according to desktop paradigm.
6192 * @method onEventSelectRow
6193 * @param oArgs.event {HTMLEvent} Event object.
6194 * @param oArgs.target {HTMLElement} Target element.
6196 YAHOO.widget.DataTable.prototype.onEventSelectRow = function(oArgs) {
6197 var sMode = this.get("selectionMode");
6198 if ((sMode == "singlecell") || (sMode == "cellblock") || (sMode == "cellrange")) {
6202 var evt = oArgs.event;
6203 var elTarget = oArgs.target;
6205 var bSHIFT = evt.shiftKey;
6206 var bCTRL = evt.ctrlKey;
6207 var i, nAnchorTrIndex;
6209 // Validate target row
6210 var elTargetRow = this.getTrEl(elTarget);
6212 var allRows = this._elTbody.rows;
6213 var nTargetTrIndex = elTargetRow.sectionRowIndex;
6214 var elAnchorRow = YAHOO.util.Dom.get(this._sSelectionAnchorId);
6216 // Both SHIFT and CTRL
6217 if((sMode != "single") && bSHIFT && bCTRL) {
6218 // Validate anchor row
6219 if(elAnchorRow && YAHOO.lang.isNumber(elAnchorRow.sectionRowIndex)) {
6220 nAnchorTrIndex = elAnchorRow.sectionRowIndex;
6221 if(this.isSelected(elAnchorRow)) {
6222 // Select all rows between anchor row and target row, including target row
6223 if(nAnchorTrIndex < nTargetTrIndex) {
6224 for(i=nAnchorTrIndex+1; i<=nTargetTrIndex; i++) {
6225 if(!this.isSelected(allRows[i])) {
6226 this.selectRow(allRows[i]);
6230 // Select all rows between target row and anchor row, including target row
6232 for(i=nAnchorTrIndex-1; i>=nTargetTrIndex; i--) {
6233 if(!this.isSelected(allRows[i])) {
6234 this.selectRow(allRows[i]);
6240 // Unselect all rows between anchor row and target row
6241 if(nAnchorTrIndex < nTargetTrIndex) {
6242 for(i=nAnchorTrIndex+1; i<=nTargetTrIndex-1; i++) {
6243 if(this.isSelected(allRows[i])) {
6244 this.unselectRow(allRows[i]);
6248 // Unselect all rows between target row and anchor row
6250 for(i=nTargetTrIndex+1; i<=nAnchorTrIndex-1; i++) {
6251 if(this.isSelected(allRows[i])) {
6252 this.unselectRow(allRows[i]);
6256 // Select the target row
6257 this.selectRow(elTargetRow);
6263 this._sSelectionAnchorId = elTargetRow.id;
6265 // Toggle selection of target
6266 if(this.isSelected(elTargetRow)) {
6267 this.unselectRow(elTargetRow);
6270 this.selectRow(elTargetRow);
6275 else if((sMode != "single") && bSHIFT) {
6276 this.unselectAllRows();
6279 if(elAnchorRow && YAHOO.lang.isNumber(elAnchorRow.sectionRowIndex)) {
6280 nAnchorTrIndex = elAnchorRow.sectionRowIndex;
6282 // Select all rows between anchor row and target row,
6283 // including the anchor row and target row
6284 if(nAnchorTrIndex < nTargetTrIndex) {
6285 for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
6286 this.selectRow(allRows[i]);
6289 // Select all rows between target row and anchor row,
6290 // including the target row and anchor row
6292 for(i=nAnchorTrIndex; i>=nTargetTrIndex; i--) {
6293 this.selectRow(allRows[i]);
6300 this._sSelectionAnchorId = elTargetRow.id;
6302 // Select target row only
6303 this.selectRow(elTargetRow);
6307 else if((sMode != "single") && bCTRL) {
6309 this._sSelectionAnchorId = elTargetRow.id;
6311 // Toggle selection of target
6312 if(this.isSelected(elTargetRow)) {
6313 this.unselectRow(elTargetRow);
6316 this.selectRow(elTargetRow);
6319 // Neither SHIFT nor CTRL
6320 else if(sMode == "single") {
6321 this.unselectAllRows();
6322 this.selectRow(elTargetRow);
6324 // Neither SHIFT nor CTRL
6327 this._sSelectionAnchorId = elTargetRow.id;
6329 // Select only target
6330 this.unselectAllRows();
6331 this.selectRow(elTargetRow);
6333 YAHOO.util.Event.stopEvent(evt);
6335 // Clear any selections that are a byproduct of the click or dblclick
6337 if(window.getSelection) {
6338 sel = window.getSelection();
6340 else if(document.getSelection) {
6341 sel = document.getSelection();
6343 else if(document.selection) {
6344 sel = document.selection;
6350 else if (sel.removeAllRanges) {
6351 sel.removeAllRanges();
6353 else if(sel.collapse) {
6359 YAHOO.log("Could not select row " + elTarget, "warn", this.toString());
6364 * Overridable custom event handler to select cell.
6366 * @method onEventSelectCell
6367 * @param oArgs.event {HTMLEvent} Event object.
6368 * @param oArgs.target {HTMLElement} Target element.
6370 YAHOO.widget.DataTable.prototype.onEventSelectCell = function(oArgs) {
6371 var sMode = this.get("selectionMode");
6372 if ((sMode == "standard") || (sMode == "single")) {
6376 var evt = oArgs.event;
6377 var elTarget = oArgs.target;
6379 var bSHIFT = evt.shiftKey;
6380 var bCTRL = evt.ctrlKey;
6381 var i, j, nAnchorTrIndex, nAnchorTdIndex, currentRow, startIndex, endIndex;
6383 var elTargetCell = this.getTdEl(elTarget);
6385 var elTargetRow = this.getTrEl(elTargetCell);
6386 var allRows = this._elTbody.rows;
6387 var nTargetTrIndex = elTargetRow.sectionRowIndex;
6388 var nTargetTdIndex = elTarget.yuiCellIndex;
6389 var elAnchorCell = YAHOO.util.Dom.get(this._sSelectionAnchorId);
6391 // Both SHIFT and CTRL
6392 if((sMode != "singlecell") && bSHIFT && bCTRL) {
6394 if(elAnchorCell && YAHOO.lang.isNumber(elAnchorCell.yuiCellIndex)) {
6395 nAnchorTrIndex = elAnchorCell.parentNode.sectionRowIndex;
6396 nAnchorTdIndex = elAnchorCell.yuiCellIndex;
6398 // Anchor is selected
6399 if(this.isSelected(elAnchorCell)) {
6400 // All cells are on the same row
6401 if(nAnchorTrIndex == nTargetTrIndex) {
6402 // Select all cells between anchor cell and target cell, including target cell
6403 if(nAnchorTdIndex < nTargetTdIndex) {
6404 for(i=nAnchorTdIndex+1; i<=nTargetTdIndex; i++) {
6405 this.selectCell(allRows[nTargetTrIndex].cells[i]);
6408 // Select all cells between target cell and anchor cell, including target cell
6409 else if(nTargetTdIndex < nAnchorTdIndex) {
6410 for(i=nTargetTdIndex; i<nAnchorTdIndex; i++) {
6411 this.selectCell(allRows[nTargetTrIndex].cells[i]);
6415 // Anchor row is above target row
6416 else if(nAnchorTrIndex < nTargetTrIndex) {
6417 if(sMode == "cellrange") {
6418 // Select all cells on anchor row from anchor cell to the end of the row
6419 for(i=nAnchorTdIndex+1; i<allRows[nAnchorTrIndex].cells.length; i++) {
6420 this.selectCell(allRows[nAnchorTrIndex].cells[i]);
6423 // Select all cells on all rows between anchor row and target row
6424 for(i=nAnchorTrIndex+1; i<nTargetTrIndex; i++) {
6425 for(j=0; j<allRows[i].cells.length; j++){
6426 this.selectCell(allRows[i].cells[j]);
6430 // Select all cells on target row from first cell to the target cell
6431 for(i=0; i<=nTargetTdIndex; i++) {
6432 this.selectCell(allRows[nTargetTrIndex].cells[i]);
6435 else if(sMode == "cellblock") {
6436 startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
6437 endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);
6439 // Select all cells from startIndex to endIndex on rows between anchor row and target row
6440 for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
6441 for(j=startIndex; j<=endIndex; j++) {
6442 this.selectCell(allRows[i].cells[j]);
6447 // Anchor row is below target row
6449 if(sMode == "cellrange") {
6450 // Select all cells on target row from target cell to the end of the row
6451 for(i=nTargetTdIndex; i<allRows[nTargetTrIndex].cells.length; i++) {
6452 this.selectCell(allRows[nTargetTrIndex].cells[i]);
6455 // Select all cells on all rows between target row and anchor row
6456 for(i=nTargetTrIndex+1; i<nAnchorTrIndex; i++) {
6457 for(j=0; j<allRows[i].cells.length; j++){
6458 this.selectCell(allRows[i].cells[j]);
6462 // Select all cells on anchor row from first cell to the anchor cell
6463 for(i=0; i<nAnchorTdIndex; i++) {
6464 this.selectCell(allRows[nAnchorTrIndex].cells[i]);
6467 else if(sMode == "cellblock") {
6468 startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
6469 endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);
6471 // Select all cells from startIndex to endIndex on rows between target row and anchor row
6472 for(i=nAnchorTrIndex; i>=nTargetTrIndex; i--) {
6473 for(j=endIndex; j>=startIndex; j--) {
6474 this.selectCell(allRows[i].cells[j]);
6480 // Anchor cell is unselected
6482 // All cells are on the same row
6483 if(nAnchorTrIndex == nTargetTrIndex) {
6484 // Unselect all cells between anchor cell and target cell
6485 if(nAnchorTdIndex < nTargetTdIndex) {
6486 for(i=nAnchorTdIndex+1; i<nTargetTdIndex; i++) {
6487 this.unselectCell(allRows[nTargetTrIndex].cells[i]);
6490 // Select all cells between target cell and anchor cell
6491 else if(nTargetTdIndex < nAnchorTdIndex) {
6492 for(i=nTargetTdIndex+1; i<nAnchorTdIndex; i++) {
6493 this.unselectCell(allRows[nTargetTrIndex].cells[i]);
6497 // Anchor row is above target row
6498 if(nAnchorTrIndex < nTargetTrIndex) {
6499 // Unselect all cells from anchor cell to target cell
6500 for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
6501 currentRow = allRows[i];
6502 for(j=0; j<currentRow.cells.length; j++) {
6503 // This is the anchor row, only unselect cells after the anchor cell
6504 if(currentRow.sectionRowIndex == nAnchorTrIndex) {
6505 if(j>nAnchorTdIndex) {
6506 this.unselectCell(currentRow.cells[j]);
6509 // This is the target row, only unelect cells before the target cell
6510 else if(currentRow.sectionRowIndex == nTargetTrIndex) {
6511 if(j<nTargetTdIndex) {
6512 this.unselectCell(currentRow.cells[j]);
6515 // Unselect all cells on this row
6517 this.unselectCell(currentRow.cells[j]);
6522 // Anchor row is below target row
6524 // Unselect all cells from target cell to anchor cell
6525 for(i=nTargetTrIndex; i<=nAnchorTrIndex; i++) {
6526 currentRow = allRows[i];
6527 for(j=0; j<currentRow.cells.length; j++) {
6528 // This is the target row, only unselect cells after the target cell
6529 if(currentRow.sectionRowIndex == nTargetTrIndex) {
6530 if(j>nTargetTdIndex) {
6531 this.unselectCell(currentRow.cells[j]);
6534 // This is the anchor row, only unselect cells before the anchor cell
6535 else if(currentRow.sectionRowIndex == nAnchorTrIndex) {
6536 if(j<nAnchorTdIndex) {
6537 this.unselectCell(currentRow.cells[j]);
6540 // Unselect all cells on this row
6542 this.unselectCell(currentRow.cells[j]);
6548 // Select the target cell
6549 this.selectCell(elTargetCell);
6555 this._sSelectionAnchorId = elTargetCell.id;
6557 // Toggle selection of target
6558 if(this.isSelected(elTargetCell)) {
6559 this.unselectCell(elTargetCell);
6562 this.selectCell(elTargetCell);
6567 else if((sMode != "singlecell") && bSHIFT) {
6568 this.unselectAllCells();
6571 if(elAnchorCell && YAHOO.lang.isNumber(elAnchorCell.yuiCellIndex)) {
6572 nAnchorTrIndex = elAnchorCell.parentNode.sectionRowIndex;
6573 nAnchorTdIndex = elAnchorCell.yuiCellIndex;
6575 // All cells are on the same row
6576 if(nAnchorTrIndex == nTargetTrIndex) {
6577 // Select all cells between anchor cell and target cell,
6578 // including the anchor cell and target cell
6579 if(nAnchorTdIndex < nTargetTdIndex) {
6580 for(i=nAnchorTdIndex; i<=nTargetTdIndex; i++) {
6581 this.selectCell(allRows[nTargetTrIndex].cells[i]);
6584 // Select all cells between target cell and anchor cell
6585 // including the target cell and anchor cell
6586 else if(nTargetTdIndex < nAnchorTdIndex) {
6587 for(i=nTargetTdIndex; i<=nAnchorTdIndex; i++) {
6588 this.selectCell(allRows[nTargetTrIndex].cells[i]);
6592 // Anchor row is above target row
6593 else if(nAnchorTrIndex < nTargetTrIndex) {
6594 if(sMode == "cellrange") {
6595 // Select all cells from anchor cell to target cell
6596 // including the anchor cell and target cell
6597 for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
6598 currentRow = allRows[i];
6599 for(j=0; j<currentRow.cells.length; j++) {
6600 // This is the anchor row, only select the anchor cell and after
6601 if(currentRow.sectionRowIndex == nAnchorTrIndex) {
6602 if(j>=nAnchorTdIndex) {
6603 this.selectCell(currentRow.cells[j]);
6606 // This is the target row, only select the target cell and before
6607 else if(currentRow.sectionRowIndex == nTargetTrIndex) {
6608 if(j<=nTargetTdIndex) {
6609 this.selectCell(currentRow.cells[j]);
6612 // Select all cells on this row
6614 this.selectCell(currentRow.cells[j]);
6619 else if(sMode == "cellblock") {
6620 // Select the cellblock from anchor cell to target cell
6621 // including the anchor cell and the target cell
6622 startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
6623 endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);
6625 for(i=nAnchorTrIndex; i<=nTargetTrIndex; i++) {
6626 for(j=startIndex; j<=endIndex; j++) {
6627 this.selectCell(allRows[i].cells[j]);
6631 this._sLastSelectedId = allRows[nTargetTrIndex].cells[nTargetTdIndex].id;
6634 // Anchor row is below target row
6636 if(sMode == "cellrange") {
6637 // Select all cells from target cell to anchor cell,
6638 // including the target cell and anchor cell
6639 for(i=nTargetTrIndex; i<=nAnchorTrIndex; i++) {
6640 currentRow = allRows[i];
6641 for(j=0; j<currentRow.cells.length; j++) {
6642 // This is the target row, only select the target cell and after
6643 if(currentRow.sectionRowIndex == nTargetTrIndex) {
6644 if(j>=nTargetTdIndex) {
6645 this.selectCell(currentRow.cells[j]);
6648 // This is the anchor row, only select the anchor cell and before
6649 else if(currentRow.sectionRowIndex == nAnchorTrIndex) {
6650 if(j<=nAnchorTdIndex) {
6651 this.selectCell(currentRow.cells[j]);
6654 // Select all cells on this row
6656 this.selectCell(currentRow.cells[j]);
6661 else if(sMode == "cellblock") {
6662 // Select the cellblock from target cell to anchor cell
6663 // including the target cell and the anchor cell
6664 startIndex = Math.min(nAnchorTdIndex, nTargetTdIndex);
6665 endIndex = Math.max(nAnchorTdIndex, nTargetTdIndex);
6667 for(i=nTargetTrIndex; i<=nAnchorTrIndex; i++) {
6668 for(j=startIndex; j<=endIndex; j++) {
6669 this.selectCell(allRows[i].cells[j]);
6673 this._sLastSelectedId = allRows[nTargetTrIndex].cells[nTargetTdIndex].id;
6680 this._sSelectionAnchorId = elTargetCell.id;
6682 // Select target only
6683 this.selectCell(elTargetCell);
6687 else if((sMode != "singlecell") && bCTRL) {
6689 this._sSelectionAnchorId = elTargetCell.id;
6691 // Toggle selection of target
6692 if(this.isSelected(elTargetCell)) {
6693 this.unselectCell(elTargetCell);
6696 this.selectCell(elTargetCell);
6699 // Neither SHIFT nor CTRL, or multi-selection has been disabled
6702 this._sSelectionAnchorId = elTargetCell.id;
6704 // Select only target
6705 this.unselectAllCells();
6706 this.selectCell(elTargetCell);
6709 YAHOO.util.Event.stopEvent(evt);
6711 // Clear any selections that are a byproduct of the click or dblclick
6713 if(window.getSelection) {
6714 sel = window.getSelection();
6716 else if(document.getSelection) {
6717 sel = document.getSelection();
6719 else if(document.selection) {
6720 sel = document.selection;
6726 else if (sel.removeAllRanges) {
6727 sel.removeAllRanges();
6729 else if(sel.collapse) {
6735 YAHOO.log("Could not select cell " + elTarget, "warn", this.toString());
6750 * Overridable custom event handler to highlight row.
6752 * @method onEventHighlightRow
6753 * @param oArgs.event {HTMLEvent} Event object.
6754 * @param oArgs.target {HTMLElement} Target element.
6756 YAHOO.widget.DataTable.prototype.onEventHighlightRow = function(oArgs) {
6757 var evt = oArgs.event;
6758 var elTarget = oArgs.target;
6759 this.highlightRow(elTarget);
6763 * Overridable custom event handler to unhighlight row.
6765 * @method onEventUnhighlightRow
6766 * @param oArgs.event {HTMLEvent} Event object.
6767 * @param oArgs.target {HTMLElement} Target element.
6769 YAHOO.widget.DataTable.prototype.onEventUnhighlightRow = function(oArgs) {
6770 var evt = oArgs.event;
6771 var elTarget = oArgs.target;
6772 this.unhighlightRow(elTarget);
6776 * Overridable custom event handler to highlight cell.
6778 * @method onEventHighlightCell
6779 * @param oArgs.event {HTMLEvent} Event object.
6780 * @param oArgs.target {HTMLElement} Target element.
6782 YAHOO.widget.DataTable.prototype.onEventHighlightCell = function(oArgs) {
6783 var evt = oArgs.event;
6784 var elTarget = oArgs.target;
6785 this.highlightCell(elTarget);
6789 * Overridable custom event handler to unhighlight cell.
6791 * @method onEventUnhighlightCell
6792 * @param oArgs.event {HTMLEvent} Event object.
6793 * @param oArgs.target {HTMLElement} Target element.
6795 YAHOO.widget.DataTable.prototype.onEventUnhighlightCell = function(oArgs) {
6796 var evt = oArgs.event;
6797 var elTarget = oArgs.target;
6798 this.unhighlightCell(elTarget);
6802 * Overridable custom event handler to format cell.
6804 * @method onEventFormatCell
6805 * @param oArgs.event {HTMLEvent} Event object.
6806 * @param oArgs.target {HTMLElement} Target element.
6808 YAHOO.widget.DataTable.prototype.onEventFormatCell = function(oArgs) {
6809 var evt = oArgs.event;
6810 var target = oArgs.target;
6811 var elTag = target.tagName.toLowerCase();
6813 var elCell = this.getTdEl(target);
6814 if(elCell && YAHOO.lang.isNumber(elCell.yuiColumnId)) {
6815 var oColumn = this._oColumnSet.getColumn(elCell.yuiColumnId);
6816 this.formatCell(elCell, this.getRecord(elCell), oColumn);
6819 YAHOO.log("Could not format cell " + target, "warn", this.toString());
6824 * Overridable custom event handler to edit cell.
6826 * @method onEventShowCellEditor
6827 * @param oArgs.event {HTMLEvent} Event object.
6828 * @param oArgs.target {HTMLElement} Target element.
6830 YAHOO.widget.DataTable.prototype.onEventShowCellEditor = function(oArgs) {
6831 var evt = oArgs.event;
6832 var target = oArgs.target;
6833 var elTag = target.tagName.toLowerCase();
6835 var elCell = this.getTdEl(target);
6837 this.showCellEditor(elCell);
6840 YAHOO.log("Could not edit cell " + target, "warn", this.toString());
6843 // Backward compatibility
6844 YAHOO.widget.DataTable.prototype.onEventEditCell = function(oArgs) {
6845 YAHOO.log("The method onEventEditCell() has been deprecated" +
6846 " in favor of onEventShowCellEditor()", "warn", this.toString());
6847 this.onEventShowCellEditor(oArgs);
6851 * Overridable custom event handler to save Cell Editor input.
6853 * @method onEventSaveCellEditor
6854 * @param oArgs.editor {Object} Cell Editor object literal.
6856 YAHOO.widget.DataTable.prototype.onEventSaveCellEditor = function(oArgs) {
6857 this.saveCellEditor();
6861 * Callback function for creating a progressively enhanced DataTable first
6862 * receives data from DataSource and populates the RecordSet, then initializes
6865 * @method _onDataReturnEnhanceTable
6866 * @param sRequest {String} Original request.
6867 * @param oResponse {Object} Response object.
6868 * @param bError {Boolean} (optional) True if there was a data error.
6871 YAHOO.widget.DataTable.prototype._onDataReturnEnhanceTable = function(sRequest, oResponse) {
6872 // Pass data through abstract method for any transformations
6873 var ok = this.doBeforeLoadData(sRequest, oResponse);
6875 // Data ok to populate
6876 if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
6878 this._oRecordSet.addRecords(oResponse.results);
6880 // Initialize DOM elements
6881 this._initTableEl();
6882 if(!this._elTable || !this._elThead || !this._elTbody) {
6883 YAHOO.log("Could not instantiate DataTable due to an invalid DOM elements", "error", this.toString());
6887 // Call Element's constructor after DOM elements are created
6888 // but *before* UI is updated with data
6889 YAHOO.widget.DataTable.superclass.constructor.call(this, this._elContainer, this._oConfigs);
6891 //HACK: Set the Paginator values
6892 if(this._oConfigs.paginator) {
6893 this.updatePaginator(this._oConfigs.paginator);
6900 else if(ok && oResponse.error) {
6901 this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
6905 this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
6910 * Callback function receives data from DataSource and populates an entire
6911 * DataTable with Records and TR elements, clearing previous Records, if any.
6913 * @method onDataReturnInitializeTable
6914 * @param sRequest {String} Original request.
6915 * @param oResponse {Object} Response object.
6916 * @param bError {Boolean} (optional) True if there was a data error.
6918 YAHOO.widget.DataTable.prototype.onDataReturnInitializeTable = function(sRequest, oResponse) {
6919 this.fireEvent("dataReturnEvent", {request:sRequest,response:oResponse});
6921 // Pass data through abstract method for any transformations
6922 var ok = this.doBeforeLoadData(sRequest, oResponse);
6924 // Data ok to populate
6925 if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
6926 this.initializeTable(oResponse.results);
6929 else if(ok && oResponse.error) {
6930 this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
6934 this.showTableMessage(YAHOO.widget.DataTable.MSG_EMPTY, YAHOO.widget.DataTable.CLASS_EMPTY);
6937 // Backward compatibility
6938 YAHOO.widget.DataTable.prototype.onDataReturnReplaceRows = function(sRequest, oResponse) {
6939 YAHOO.log("The method onDataReturnReplaceRows() has been deprecated" +
6940 " in favor of onDataReturnInitializeTable()", "warn", this.toString());
6941 this.onDataReturnInitializeTable(sRequest, oResponse);
6945 * Callback function receives data from DataSource and appends to an existing
6946 * DataTable new Records and, if applicable, creates or updates
6947 * corresponding TR elements.
6949 * @method onDataReturnAppendRows
6950 * @param sRequest {String} Original request.
6951 * @param oResponse {Object} Response object.
6952 * @param bError {Boolean} (optional) True if there was a data error.
6954 YAHOO.widget.DataTable.prototype.onDataReturnAppendRows = function(sRequest, oResponse) {
6955 this.fireEvent("dataReturnEvent", {request:sRequest,response:oResponse});
6957 // Pass data through abstract method for any transformations
6958 var ok = this.doBeforeLoadData(sRequest, oResponse);
6960 // Data ok to append
6961 if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
6962 this.addRows(oResponse.results);
6965 else if(ok && oResponse.error) {
6966 this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
6971 * Callback function receives data from DataSource and inserts into top of an
6972 * existing DataTable new Records and, if applicable, creates or updates
6973 * corresponding TR elements.
6975 * @method onDataReturnInsertRows
6976 * @param sRequest {String} Original request.
6977 * @param oResponse {Object} Response object.
6978 * @param bError {Boolean} (optional) True if there was a data error.
6980 YAHOO.widget.DataTable.prototype.onDataReturnInsertRows = function(sRequest, oResponse) {
6981 this.fireEvent("dataReturnEvent", {request:sRequest,response:oResponse});
6983 // Pass data through abstract method for any transformations
6984 var ok = this.doBeforeLoadData(sRequest, oResponse);
6986 // Data ok to append
6987 if(ok && oResponse && !oResponse.error && YAHOO.lang.isArray(oResponse.results)) {
6988 this.addRows(oResponse.results, 0);
6991 else if(ok && oResponse.error) {
6992 this.showTableMessage(YAHOO.widget.DataTable.MSG_ERROR, YAHOO.widget.DataTable.CLASS_ERROR);
7030 /////////////////////////////////////////////////////////////////////////////
7034 /////////////////////////////////////////////////////////////////////////////
7037 * Fired when the DataTable instance's initialization is complete.
7043 * Fired when the DataTable's view is refreshed.
7045 * @event refreshEvent
7049 * Fired when data is returned from DataSource.
7051 * @event dataReturnEvent
7052 * @param oArgs.request {String} Original request.
7053 * @param oArgs.response {Object} Response object.
7057 * Fired when the DataTable has a focus.
7059 * @event tableFocusEvent
7063 * Fired when the DataTable has a blur.
7065 * @event tableBlurEvent
7069 * Fired when the DataTable has a mouseover.
7071 * @event tableMouseoverEvent
7072 * @param oArgs.event {HTMLEvent} The event object.
7073 * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
7078 * Fired when the DataTable has a mouseout.
7080 * @event tableMouseoutEvent
7081 * @param oArgs.event {HTMLEvent} The event object.
7082 * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
7087 * Fired when the DataTable has a mousedown.
7089 * @event tableMousedownEvent
7090 * @param oArgs.event {HTMLEvent} The event object.
7091 * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
7096 * Fired when the DataTable has a click.
7098 * @event tableClickEvent
7099 * @param oArgs.event {HTMLEvent} The event object.
7100 * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
7105 * Fired when the DataTable has a dblclick.
7107 * @event tableDblclickEvent
7108 * @param oArgs.event {HTMLEvent} The event object.
7109 * @param oArgs.target {HTMLElement} The DataTable's TABLE element.
7114 * Fired when a fixed scrolling DataTable has a scroll.
7116 * @event tableScrollEvent
7117 * @param oArgs.event {HTMLEvent} The event object.
7118 * @param oArgs.target {HTMLElement} The DataTable's CONTAINER element (in IE)
7119 * or the DataTable's TBODY element (everyone else).
7124 * Fired when a message is shown in the DataTable's message element.
7126 * @event tableMsgShowEvent
7127 * @param oArgs.html {String} The HTML displayed.
7128 * @param oArgs.className {String} The className assigned.
7133 * Fired when the DataTable's message element is hidden.
7135 * @event tableMsgHideEvent
7139 * Fired when a header row has a mouseover.
7141 * @event headerRowMouseoverEvent
7142 * @param oArgs.event {HTMLEvent} The event object.
7143 * @param oArgs.target {HTMLElement} The TR element.
7147 * Fired when a header row has a mouseout.
7149 * @event headerRowMouseoutEvent
7150 * @param oArgs.event {HTMLEvent} The event object.
7151 * @param oArgs.target {HTMLElement} The TR element.
7155 * Fired when a header row has a mousedown.
7157 * @event headerRowMousedownEvent
7158 * @param oArgs.event {HTMLEvent} The event object.
7159 * @param oArgs.target {HTMLElement} The TR element.
7163 * Fired when a header row has a click.
7165 * @event headerRowClickEvent
7166 * @param oArgs.event {HTMLEvent} The event object.
7167 * @param oArgs.target {HTMLElement} The TR element.
7171 * Fired when a header row has a dblclick.
7173 * @event headerRowDblclickEvent
7174 * @param oArgs.event {HTMLEvent} The event object.
7175 * @param oArgs.target {HTMLElement} The TR element.
7179 * Fired when a header cell has a mouseover.
7181 * @event headerCellMouseoverEvent
7182 * @param oArgs.event {HTMLEvent} The event object.
7183 * @param oArgs.target {HTMLElement} The TH element.
7188 * Fired when a header cell has a mouseout.
7190 * @event headerCellMouseoutEvent
7191 * @param oArgs.event {HTMLEvent} The event object.
7192 * @param oArgs.target {HTMLElement} The TH element.
7197 * Fired when a header cell has a mousedown.
7199 * @event headerCellMousedownEvent
7200 * @param oArgs.event {HTMLEvent} The event object.
7201 * @param oArgs.target {HTMLElement} The TH element.
7205 * Fired when a header cell has a click.
7207 * @event headerCellClickEvent
7208 * @param oArgs.event {HTMLEvent} The event object.
7209 * @param oArgs.target {HTMLElement} The TH element.
7213 * Fired when a header cell has a dblclick.
7215 * @event headerCellDblclickEvent
7216 * @param oArgs.event {HTMLEvent} The event object.
7217 * @param oArgs.target {HTMLElement} The TH element.
7221 * Fired when a header label has a mouseover.
7223 * @event headerLabelMouseoverEvent
7224 * @param oArgs.event {HTMLEvent} The event object.
7225 * @param oArgs.target {HTMLElement} The SPAN element.
7230 * Fired when a header label has a mouseout.
7232 * @event headerLabelMouseoutEvent
7233 * @param oArgs.event {HTMLEvent} The event object.
7234 * @param oArgs.target {HTMLElement} The SPAN element.
7239 * Fired when a header label has a mousedown.
7241 * @event headerLabelMousedownEvent
7242 * @param oArgs.event {HTMLEvent} The event object.
7243 * @param oArgs.target {HTMLElement} The SPAN element.
7247 * Fired when a header label has a click.
7249 * @event headerLabelClickEvent
7250 * @param oArgs.event {HTMLEvent} The event object.
7251 * @param oArgs.target {HTMLElement} The SPAN element.
7255 * Fired when a header label has a dblclick.
7257 * @event headerLabelDblclickEvent
7258 * @param oArgs.event {HTMLEvent} The event object.
7259 * @param oArgs.target {HTMLElement} The SPAN element.
7263 * Fired when a column is sorted.
7265 * @event columnSortEvent
7266 * @param oArgs.column {YAHOO.widget.Column} The Column instance.
7267 * @param oArgs.dir {String} Sort direction "asc" or "desc".
7271 * Fired when a column is resized.
7273 * @event columnResizeEvent
7274 * @param oArgs.column {YAHOO.widget.Column} The Column instance.
7275 * @param oArgs.target {HTMLElement} The TH element.
7279 * Fired when a row has a mouseover.
7281 * @event rowMouseoverEvent
7282 * @param oArgs.event {HTMLEvent} The event object.
7283 * @param oArgs.target {HTMLElement} The TR element.
7287 * Fired when a row has a mouseout.
7289 * @event rowMouseoutEvent
7290 * @param oArgs.event {HTMLEvent} The event object.
7291 * @param oArgs.target {HTMLElement} The TR element.
7295 * Fired when a row has a mousedown.
7297 * @event rowMousedownEvent
7298 * @param oArgs.event {HTMLEvent} The event object.
7299 * @param oArgs.target {HTMLElement} The TR element.
7303 * Fired when a row has a click.
7305 * @event rowClickEvent
7306 * @param oArgs.event {HTMLEvent} The event object.
7307 * @param oArgs.target {HTMLElement} The TR element.
7311 * Fired when a row has a dblclick.
7313 * @event rowDblclickEvent
7314 * @param oArgs.event {HTMLEvent} The event object.
7315 * @param oArgs.target {HTMLElement} The TR element.
7319 * Fired when a row is added.
7321 * @event rowAddEvent
7322 * @param oArgs.record {YAHOO.widget.Record} The added Record.
7326 * Fired when a row is updated.
7328 * @event rowUpdateEvent
7329 * @param oArgs.record {YAHOO.widget.Record} The updated Record.
7330 * @param oArgs.oldData {Object} Object literal of the old data.
7334 * Fired when a row is deleted.
7336 * @event rowDeleteEvent
7337 * @param oArgs.oldData {Object} Object literal of the deleted data.
7338 * @param oArgs.recordIndex {Number} Index of the deleted Record.
7339 * @param oArgs.trElIndex {Number} Index of the deleted TR element, if in view.
7343 * Fired when a row is selected.
7345 * @event rowSelectEvent
7346 * @param oArgs.el {HTMLElement} The selected TR element, if applicable.
7347 * @param oArgs.record {YAHOO.widget.Record} The selected Record.
7351 * Fired when a row is unselected.
7353 * @event rowUnselectEvent
7354 * @param oArgs.el {HTMLElement} The unselected TR element, if applicable.
7355 * @param oArgs.record {YAHOO.widget.Record} The unselected Record.
7358 /*TODO: delete and use rowUnselectEvent?
7359 * Fired when all row selections are cleared.
7361 * @event unselectAllRowsEvent
7365 * Fired when a row is highlighted.
7367 * @event rowHighlightEvent
7368 * @param oArgs.el {HTMLElement} The highlighted TR element.
7369 * @param oArgs.record {YAHOO.widget.Record} The highlighted Record.
7373 * Fired when a row is unhighlighted.
7375 * @event rowUnhighlightEvent
7376 * @param oArgs.el {HTMLElement} The highlighted TR element.
7377 * @param oArgs.record {YAHOO.widget.Record} The highlighted Record.
7381 * Fired when a cell has a mouseover.
7383 * @event cellMouseoverEvent
7384 * @param oArgs.event {HTMLEvent} The event object.
7385 * @param oArgs.target {HTMLElement} The TD element.
7389 * Fired when a cell has a mouseout.
7391 * @event cellMouseoutEvent
7392 * @param oArgs.event {HTMLEvent} The event object.
7393 * @param oArgs.target {HTMLElement} The TD element.
7397 * Fired when a cell has a mousedown.
7399 * @event cellMousedownEvent
7400 * @param oArgs.event {HTMLEvent} The event object.
7401 * @param oArgs.target {HTMLElement} The TD element.
7405 * Fired when a cell has a click.
7407 * @event cellClickEvent
7408 * @param oArgs.event {HTMLEvent} The event object.
7409 * @param oArgs.target {HTMLElement} The TD element.
7413 * Fired when a cell has a dblclick.
7415 * @event cellDblclickEvent
7416 * @param oArgs.event {HTMLEvent} The event object.
7417 * @param oArgs.target {HTMLElement} The TD element.
7421 * Fired when a cell is formatted.
7423 * @event cellFormatEvent
7424 * @param oArgs.el {HTMLElement} The formatted TD element.
7425 * @param oArgs.record {YAHOO.widget.Record} The formatted Record.
7426 * @param oArgs.key {String} The key of the formatted cell.
7430 * Fired when a cell is selected.
7432 * @event cellSelectEvent
7433 * @param oArgs.el {HTMLElement} The selected TD element.
7434 * @param oArgs.record {YAHOO.widget.Record} The selected Record.
7435 * @param oArgs.key {String} The key of the selected cell.
7439 * Fired when a cell is unselected.
7441 * @event cellUnselectEvent
7442 * @param oArgs.el {HTMLElement} The unselected TD element.
7443 * @param oArgs.record {YAHOO.widget.Record} The unselected Record.
7444 * @param oArgs.key {String} The key of the unselected cell.
7448 * Fired when a cell is highlighted.
7450 * @event cellHighlightEvent
7451 * @param oArgs.el {HTMLElement} The highlighted TD element.
7452 * @param oArgs.record {YAHOO.widget.Record} The highlighted Record.
7453 * @param oArgs.key {String} The key of the highlighted cell.
7457 * Fired when a cell is unhighlighted.
7459 * @event cellUnhighlightEvent
7460 * @param oArgs.el {HTMLElement} The unhighlighted TD element.
7461 * @param oArgs.record {YAHOO.widget.Record} The unhighlighted Record.
7462 * @param oArgs.key {String} The key of the unhighlighted cell.
7465 /*TODO: hide from doc and use cellUnselectEvent
7466 * Fired when all cell selections are cleared.
7468 * @event unselectAllCellsEvent
7472 * Fired when DataTable paginator is updated.
7474 * @event paginatorUpdateEvent
7475 * @param paginator {Object} Object literal of Paginator values.
7479 * Fired when an Editor is activated.
7481 * @event editorShowEvent
7482 * @param oArgs.editor {Object} The Editor object literal.
7486 * Fired when an active Editor has a keydown.
7488 * @event editorKeydownEvent
7489 * @param oArgs.editor {Object} The Editor object literal.
7490 * @param oArgs.event {HTMLEvent} The event object.
7494 * Fired when Editor input is reverted.
7496 * @event editorRevertEvent
7497 * @param oArgs.editor {Object} The Editor object literal.
7498 * @param oArgs.newData {Object} New data value.
7499 * @param oArgs.oldData {Object} Old data value.
7503 * Fired when Editor input is saved.
7505 * @event editorSaveEvent
7506 * @param oArgs.editor {Object} The Editor object literal.
7507 * @param oArgs.newData {Object} New data value.
7508 * @param oArgs.oldData {Object} Old data value.
7512 * Fired when Editor input is canceled.
7514 * @event editorCancelEvent
7515 * @param oArgs.editor {Object} The Editor object literal.
7519 * Fired when an active Editor has a blur.
7521 * @event editorBlurEvent
7522 * @param oArgs.editor {Object} The Editor object literal.
7532 * Fired when a link is clicked.
7534 * @event linkClickEvent
7535 * @param oArgs.event {HTMLEvent} The event object.
7536 * @param oArgs.target {HTMLElement} The A element.
7540 * Fired when a BUTTON element is clicked.
7542 * @event buttonClickEvent
7543 * @param oArgs.event {HTMLEvent} The event object.
7544 * @param oArgs.target {HTMLElement} The BUTTON element.
7548 * Fired when a CHECKBOX element is clicked.
7550 * @event checkboxClickEvent
7551 * @param oArgs.event {HTMLEvent} The event object.
7552 * @param oArgs.target {HTMLElement} The CHECKBOX element.
7556 * Fired when a SELECT element is changed.
7558 * @event dropdownChangeEvent
7559 * @param oArgs.event {HTMLEvent} The event object.
7560 * @param oArgs.target {HTMLElement} The SELECT element.
7564 * Fired when a RADIO element is clicked.
7566 * @event radioClickEvent
7567 * @param oArgs.event {HTMLEvent} The event object.
7568 * @param oArgs.target {HTMLElement} The RADIO element.
7572 /****************************************************************************/
7573 /****************************************************************************/
7574 /****************************************************************************/
7577 * The ColumnSet class defines and manages a DataTable's Columns,
7578 * including nested hierarchies and access to individual Column instances.
7580 * @namespace YAHOO.widget
7582 * @uses YAHOO.util.EventProvider
7584 * @param aHeaders {Object[]} Array of object literals that define header cells.
7586 YAHOO.widget.ColumnSet = function(aHeaders) {
7587 this._sName = "instance" + YAHOO.widget.ColumnSet._nCount;
7589 // DOM tree representation of all Columns
7591 // Flat representation of all Columns
7593 // Flat representation of only Columns that are meant to display data
7595 // Array of HEADERS attribute values for all keys in the "keys" array
7598 // Tracks current node list depth being tracked
7601 // Internal recursive function to defined Column instances
7602 var parseColumns = function(nodeList, parent) {
7606 // Create corresponding tree node if not already there for this depth
7607 if(!tree[nodeDepth]) {
7608 tree[nodeDepth] = [];
7612 // Parse each node at this depth for attributes and any children
7613 for(var j=0; j<nodeList.length; j++) {
7614 var currentNode = nodeList[j];
7616 // Instantiate a new Column for each node
7617 var oColumn = new YAHOO.widget.Column(currentNode);
7619 // Add the new Column to the flat list
7622 // Assign its parent as an attribute, if applicable
7624 oColumn.parent = parent;
7627 // The Column has descendants
7628 if(YAHOO.lang.isArray(currentNode.children)) {
7629 oColumn.children = currentNode.children;
7631 // Determine COLSPAN value for this Column
7632 var terminalChildNodes = 0;
7633 var countTerminalChildNodes = function(ancestor) {
7634 var descendants = ancestor.children;
7635 // Drill down each branch and count terminal nodes
7636 for(var k=0; k<descendants.length; k++) {
7637 // Keep drilling down
7638 if(YAHOO.lang.isArray(descendants[k].children)) {
7639 countTerminalChildNodes(descendants[k]);
7641 // Reached branch terminus
7643 terminalChildNodes++;
7647 countTerminalChildNodes(currentNode);
7648 oColumn._colspan = terminalChildNodes;
7650 // Cascade certain properties to children if not defined on their own
7651 var currentChildren = currentNode.children;
7652 for(var k=0; k<currentChildren.length; k++) {
7653 var child = currentChildren[k];
7654 if(oColumn.className && (child.className === undefined)) {
7655 child.className = oColumn.className;
7657 if(oColumn.editor && (child.editor === undefined)) {
7658 child.editor = oColumn.editor;
7660 if(oColumn.editorOptions && (child.editorOptions === undefined)) {
7661 child.editorOptions = oColumn.editorOptions;
7663 if(oColumn.formatter && (child.formatter === undefined)) {
7664 child.formatter = oColumn.formatter;
7666 if(oColumn.resizeable && (child.resizeable === undefined)) {
7667 child.resizeable = oColumn.resizeable;
7669 if(oColumn.sortable && (child.sortable === undefined)) {
7670 child.sortable = oColumn.sortable;
7672 if(oColumn.width && (child.width === undefined)) {
7673 child.width = oColumn.width;
7675 // Backward compatibility
7676 if(oColumn.type && (child.type === undefined)) {
7677 child.type = oColumn.type;
7679 if(oColumn.type && !oColumn.formatter) {
7680 YAHOO.log("The property type has been" +
7681 " deprecated in favor of formatter", "warn", oColumn.toString());
7682 oColumn.formatter = oColumn.type;
7684 if(oColumn.text && !YAHOO.lang.isValue(oColumn.label)) {
7685 YAHOO.log("The property text has been" +
7686 " deprecated in favor of label", "warn", oColumn.toString());
7687 oColumn.label = oColumn.text;
7689 if(oColumn.parser) {
7690 YAHOO.log("The property parser is no longer supported",
7691 "warn", this.toString());
7693 if(oColumn.sortOptions && ((oColumn.sortOptions.ascFunction) ||
7694 (oColumn.sortOptions.descFunction))) {
7695 YAHOO.log("The properties sortOptions.ascFunction and " +
7696 " sortOptions.descFunction have been deprecated in favor " +
7697 " of sortOptions.sortFunction", "warn", this.toString());
7701 // The children themselves must also be parsed for Column instances
7702 if(!tree[nodeDepth+1]) {
7703 tree[nodeDepth+1] = [];
7705 parseColumns(currentChildren, oColumn);
7707 // This Column does not have any children
7709 oColumn._nKeyIndex = keys.length;
7710 oColumn._colspan = 1;
7714 // Add the Column to the top-down tree
7715 tree[nodeDepth].push(oColumn);
7720 // Parse out Column instances from the array of object literals
7721 if(YAHOO.lang.isArray(aHeaders)) {
7722 parseColumns(aHeaders);
7725 // Determine ROWSPAN value for each Column in the tree
7726 var parseTreeForRowspan = function(tree) {
7727 var maxRowDepth = 1;
7731 // Calculate the max depth of descendants for this row
7732 var countMaxRowDepth = function(row, tmpRowDepth) {
7733 tmpRowDepth = tmpRowDepth || 1;
7735 for(var n=0; n<row.length; n++) {
7737 // Column has children, so keep counting
7738 if(YAHOO.lang.isArray(col.children)) {
7740 countMaxRowDepth(col.children, tmpRowDepth);
7743 // No children, is it the max depth?
7745 if(tmpRowDepth > maxRowDepth) {
7746 maxRowDepth = tmpRowDepth;
7753 // Count max row depth for each row
7754 for(var m=0; m<tree.length; m++) {
7755 currentRow = tree[m];
7756 countMaxRowDepth(currentRow);
7758 // Assign the right ROWSPAN values to each Column in the row
7759 for(var p=0; p<currentRow.length; p++) {
7760 currentColumn = currentRow[p];
7761 if(!YAHOO.lang.isArray(currentColumn.children)) {
7762 currentColumn._rowspan = maxRowDepth;
7765 currentColumn._rowspan = 1;
7769 // Reset counter for next row
7773 parseTreeForRowspan(tree);
7779 // Store header relationships in an array for HEADERS attribute
7780 var recurseAncestorsForHeaders = function(i, oColumn) {
7781 headers[i].push(oColumn._nId);
7782 if(oColumn.parent) {
7783 recurseAncestorsForHeaders(i, oColumn.parent);
7786 for(var i=0; i<keys.length; i++) {
7788 recurseAncestorsForHeaders(i, keys[i]);
7789 headers[i] = headers[i].reverse();
7790 headers[i] = headers[i].join(" ");
7793 // Save to the ColumnSet instance
7797 this.headers = headers;
7799 YAHOO.widget.ColumnSet._nCount++;
7800 YAHOO.log("ColumnSet initialized", "info", this.toString());
7803 /////////////////////////////////////////////////////////////////////////////
7805 // Public member variables
7807 /////////////////////////////////////////////////////////////////////////////
7810 * Internal class variable to index multiple data table instances.
7812 * @property ColumnSet._nCount
7817 YAHOO.widget.ColumnSet._nCount = 0;
7820 * Unique instance name.
7826 YAHOO.widget.ColumnSet.prototype._sName = null;
7828 /////////////////////////////////////////////////////////////////////////////
7830 // Public member variables
7832 /////////////////////////////////////////////////////////////////////////////
7835 * Top-down tree representation of Column hierarchy.
7838 * @type YAHOO.widget.Column[]
7840 YAHOO.widget.ColumnSet.prototype.tree = null;
7843 * Flattened representation of all Columns.
7846 * @type YAHOO.widget.Column[]
7849 YAHOO.widget.ColumnSet.prototype.flat = null;
7852 * Array of Columns that map one-to-one to a table column.
7855 * @type YAHOO.widget.Column[]
7858 YAHOO.widget.ColumnSet.prototype.keys = null;
7861 * ID index of nested parent hierarchies for HEADERS accessibility attribute.
7867 YAHOO.widget.ColumnSet.prototype.headers = null;
7869 /////////////////////////////////////////////////////////////////////////////
7873 /////////////////////////////////////////////////////////////////////////////
7876 * Public accessor to the unique name of the ColumnSet instance.
7879 * @return {String} Unique name of the ColumnSet instance.
7882 YAHOO.widget.ColumnSet.prototype.toString = function() {
7883 return "ColumnSet " + this._sName;
7887 * Returns Column instance with given ID number or key.
7890 * @param column {Number | String} ID number or unique key.
7891 * @return {YAHOO.widget.Column} Column instance.
7894 YAHOO.widget.ColumnSet.prototype.getColumn = function(column) {
7895 var allColumns = this.flat;
7896 if(YAHOO.lang.isNumber(column)) {
7897 for(var i=0; i<allColumns.length; i++) {
7898 if(allColumns[i]._nId === column) {
7899 return allColumns[i];
7903 else if(YAHOO.lang.isString(column)) {
7904 for(i=0; i<allColumns.length; i++) {
7905 if(allColumns[i].key === column) {
7906 return allColumns[i];
7913 /****************************************************************************/
7914 /****************************************************************************/
7915 /****************************************************************************/
7918 * The Column class defines and manages attributes of DataTable Columns
7920 * @namespace YAHOO.widget
7923 * @param oConfigs {Object} Object literal of configuration values.
7925 YAHOO.widget.Column = function(oConfigs) {
7926 // Internal variables
7927 this._nId = YAHOO.widget.Column._nCount;
7928 this._sName = "Column instance" + this._nId;
7930 // Object literal defines Column attributes
7931 if(oConfigs && (oConfigs.constructor == Object)) {
7932 for(var sConfig in oConfigs) {
7934 this[sConfig] = oConfigs[sConfig];
7939 if(!YAHOO.lang.isValue(this.key)) {
7940 this.key = "yui-dt-column"+this._nId;
7942 YAHOO.widget.Column._nCount++;
7945 /////////////////////////////////////////////////////////////////////////////
7947 // Private member variables
7949 /////////////////////////////////////////////////////////////////////////////
7952 * Internal instance counter.
7954 * @property Column._nCount
7960 YAHOO.widget.Column._nCount = 0;
7963 * Unique instance name.
7969 YAHOO.widget.Column.prototype._sName = null;
7973 * Unique number assigned at instantiation, indicates original order within
7980 YAHOO.widget.Column.prototype._nId = null;
7983 * Reference to Column's index within its ColumnSet's keys array, or null if not applicable.
7985 * @property _nKeyIndex
7989 YAHOO.widget.Column.prototype._nKeyIndex = null;
7992 * Number of table cells the Column spans.
7994 * @property _colspan
7998 YAHOO.widget.Column.prototype._colspan = 1;
8001 * Number of table rows the Column spans.
8003 * @property _rowspan
8007 YAHOO.widget.Column.prototype._rowspan = 1;
8010 * Column's parent Column instance, or null.
8013 * @type YAHOO.widget.Column
8016 YAHOO.widget.Column.prototype._parent = null;
8019 * Current offsetWidth of the Column (in pixels).
8025 YAHOO.widget.Column.prototype._width = null;
8028 * Minimum width the Column can support (in pixels). Value is populated only if table
8029 * is fixedWidth, null otherwise.
8031 * @property _minWidth
8035 YAHOO.widget.Column.prototype._minWidth = null;
8037 /////////////////////////////////////////////////////////////////////////////
8039 // Public member variables
8041 /////////////////////////////////////////////////////////////////////////////
8044 * Associated database field, or null.
8049 YAHOO.widget.Column.prototype.key = null;
8052 * Text or HTML for display as Column's label in the TH element.
8057 YAHOO.widget.Column.prototype.label = null;
8060 * Column head cell ABBR for accessibility.
8065 YAHOO.widget.Column.prototype.abbr = null;
8068 * Array of object literals that define children (nested headers) of a Column.
8070 * @property children
8073 YAHOO.widget.Column.prototype.children = null;
8081 YAHOO.widget.Column.prototype.width = null;
8084 * Custom CSS class or array of classes to be applied to every cell in the Column.
8086 * @property className
8087 * @type String || String[]
8089 YAHOO.widget.Column.prototype.className = null;
8092 * Defines a format function.
8094 * @property formatter
8095 * @type String || HTMLFunction
8097 YAHOO.widget.Column.prototype.formatter = null;
8100 * Defines an editor function, otherwise Column is not editable.
8103 * @type String || HTMLFunction
8105 YAHOO.widget.Column.prototype.editor = null;
8108 * Defines editor options for Column in an object literal of param:value pairs.
8110 * @property editorOptions
8113 YAHOO.widget.Column.prototype.editorOptions = null;
8116 * True if Column is resizeable, false otherwise.
8118 * @property resizeable
8122 YAHOO.widget.Column.prototype.resizeable = false;
8125 * True if Column is sortable, false otherwise.
8127 * @property sortable
8131 YAHOO.widget.Column.prototype.sortable = false;
8134 * Default sort order for Column: "asc" or "desc".
8136 * @property sortOptions.defaultOrder
8141 * Custom sort handler.
8143 * @property sortOptions.sortFunction
8147 YAHOO.widget.Column.prototype.sortOptions = null;
8163 /////////////////////////////////////////////////////////////////////////////
8167 /////////////////////////////////////////////////////////////////////////////
8170 * Public accessor to the unique name of the Column instance.
8173 * @return {String} Column's unique name.
8175 YAHOO.widget.Column.prototype.toString = function() {
8180 * Returns unique number assigned at instantiation, indicates original order
8184 * @return {Number} Column's unique ID number.
8186 YAHOO.widget.Column.prototype.getId = function() {
8191 * Public accessor returns Column's key index within its ColumnSet's keys array, or
8192 * null if not applicable.
8194 * @method getKeyIndex
8195 * @return {Number} Column's key index within its ColumnSet keys array, if applicable.
8197 YAHOO.widget.Column.prototype.getKeyIndex = function() {
8198 return this._nKeyIndex;
8202 * Public accessor returns Column's parent instance if any, or null otherwise.
8205 * @return {YAHOO.widget.Column} Column's parent instance.
8207 YAHOO.widget.Column.prototype.getParent = function() {
8208 return this._parent;
8212 * Public accessor returns Column's calculated COLSPAN value.
8214 * @method getColspan
8215 * @return {Number} Column's COLSPAN value.
8217 YAHOO.widget.Column.prototype.getColspan = function() {
8218 return this._colspan;
8220 // Backward compatibility
8221 YAHOO.widget.Column.prototype.getColSpan = function() {
8222 YAHOO.log("The method getColSpan() has been" +
8223 " deprecated in favor of getColspan()", "warn", this.toString());
8224 return this.getColspan();
8228 * Public accessor returns Column's calculated ROWSPAN value.
8230 * @method getRowspan
8231 * @return {Number} Column's ROWSPAN value.
8233 YAHOO.widget.Column.prototype.getRowspan = function() {
8234 return this._rowspan;
8237 // Backward compatibility
8238 YAHOO.widget.Column.prototype.getIndex = function() {
8239 YAHOO.log("The method getIndex() has been" +
8240 " deprecated in favor of getKeyIndex()", "warn",
8242 return this.getKeyIndex();
8244 YAHOO.widget.Column.prototype.format = function() {
8245 YAHOO.log("The method format() has been deprecated in favor of the " +
8246 "DataTable method formatCell()", "error", this.toString());
8248 YAHOO.widget.Column.formatCheckbox = function(elCell, oRecord, oColumn, oData) {
8249 YAHOO.log("The method YAHOO.widget.Column.formatCheckbox() has been" +
8250 " deprecated in favor of YAHOO.widget.DataTable.formatCheckbox()", "warn",
8251 "YAHOO.widget.Column.formatCheckbox");
8252 YAHOO.widget.DataTable.formatCheckbox(elCell, oRecord, oColumn, oData);
8254 YAHOO.widget.Column.formatCurrency = function(elCell, oRecord, oColumn, oData) {
8255 YAHOO.log("The method YAHOO.widget.Column.formatCurrency() has been" +
8256 " deprecated in favor of YAHOO.widget.DataTable.formatCurrency()", "warn",
8257 "YAHOO.widget.Column.formatCurrency");
8258 YAHOO.widget.DataTable.formatCurrency(elCell, oRecord, oColumn, oData);
8260 YAHOO.widget.Column.formatDate = function(elCell, oRecord, oColumn, oData) {
8261 YAHOO.log("The method YAHOO.widget.Column.formatDate() has been" +
8262 " deprecated in favor of YAHOO.widget.DataTable.formatDate()", "warn",
8263 "YAHOO.widget.Column.formatDate");
8264 YAHOO.widget.DataTable.formatDate(elCell, oRecord, oColumn, oData);
8266 YAHOO.widget.Column.formatEmail = function(elCell, oRecord, oColumn, oData) {
8267 YAHOO.log("The method YAHOO.widget.Column.formatEmail() has been" +
8268 " deprecated in favor of YAHOO.widget.DataTable.formatEmail()", "warn",
8269 "YAHOO.widget.Column.formatEmail");
8270 YAHOO.widget.DataTable.formatEmail(elCell, oRecord, oColumn, oData);
8272 YAHOO.widget.Column.formatLink = function(elCell, oRecord, oColumn, oData) {
8273 YAHOO.log("The method YAHOO.widget.Column.formatLink() has been" +
8274 " deprecated in favor of YAHOO.widget.DataTable.formatLink()", "warn",
8275 "YAHOO.widget.Column.formatLink");
8276 YAHOO.widget.DataTable.formatLink(elCell, oRecord, oColumn, oData);
8278 YAHOO.widget.Column.formatNumber = function(elCell, oRecord, oColumn, oData) {
8279 YAHOO.log("The method YAHOO.widget.Column.formatNumber() has been" +
8280 " deprecated in favor of YAHOO.widget.DataTable.formatNumber()", "warn",
8281 "YAHOO.widget.Column.formatNumber");
8282 YAHOO.widget.DataTable.formatNumber(elCell, oRecord, oColumn, oData);
8284 YAHOO.widget.Column.formatSelect = function(elCell, oRecord, oColumn, oData) {
8285 YAHOO.log("The method YAHOO.widget.Column.formatSelect() has been" +
8286 " deprecated in favor of YAHOO.widget.DataTable.formatDropdown()", "warn",
8287 "YAHOO.widget.Column.formatSelect");
8288 YAHOO.widget.DataTable.formatDropdown(elCell, oRecord, oColumn, oData);
8291 /****************************************************************************/
8292 /****************************************************************************/
8293 /****************************************************************************/
8296 * Sort static utility to support Column sorting.
8298 * @namespace YAHOO.util
8303 /////////////////////////////////////////////////////////////////////////////
8307 /////////////////////////////////////////////////////////////////////////////
8310 * Comparator function for simple case-insensitive string sorting.
8313 * @param a {Object} First sort argument.
8314 * @param b {Object} Second sort argument.
8315 * @param desc {Boolean} True if sort direction is descending, false if
8316 * sort direction is ascending.
8318 compare: function(a, b, desc) {
8319 if((a === null) || (typeof a == "undefined")) {
8320 if((b === null) || (typeof b == "undefined")) {
8327 else if((b === null) || (typeof b == "undefined")) {
8331 if(a.constructor == String) {
8332 a = a.toLowerCase();
8334 if(b.constructor == String) {
8335 b = b.toLowerCase();
8338 return (desc) ? 1 : -1;
8341 return (desc) ? -1 : 1;
8349 /****************************************************************************/
8350 /****************************************************************************/
8351 /****************************************************************************/
8354 * ColumnResizer subclasses DragDrop to support resizeable Columns.
8356 * @namespace YAHOO.util
8357 * @class ColumnResizer
8358 * @extends YAHOO.util.DragDrop
8360 * @param oDataTable {YAHOO.widget.DataTable} DataTable instance.
8361 * @param oColumn {YAHOO.widget.Column} Column instance.
8362 * @param elThead {HTMLElement} TH element reference.
8363 * @param sHandleElId {String} DOM ID of the handle element that causes the resize.
8364 * @param sGroup {String} Group name of related DragDrop items.
8365 * @param oConfig {Object} (Optional) Object literal of config values.
8367 YAHOO.util.ColumnResizer = function(oDataTable, oColumn, elThead, sHandleId, sGroup, oConfig) {
8368 if(oDataTable && oColumn && elThead && sHandleId) {
8369 this.datatable = oDataTable;
8370 this.column = oColumn;
8371 this.cell = elThead;
8372 this.init(sHandleId, sGroup, oConfig);
8374 this.setYConstraint(0,0);
8377 YAHOO.log("Column resizer could not be created due to invalid colElId","warn");
8382 YAHOO.extend(YAHOO.util.ColumnResizer, YAHOO.util.DD);
8385 /////////////////////////////////////////////////////////////////////////////
8387 // Public DOM event handlers
8389 /////////////////////////////////////////////////////////////////////////////
8392 * Handles mousedown events on the Column resizer.
8394 * @method onMouseDown
8395 * @param e {string} The mousedown event
8397 YAHOO.util.ColumnResizer.prototype.onMouseDown = function(e) {
8398 this.startWidth = this.cell.offsetWidth;
8399 this.startPos = YAHOO.util.Dom.getX(this.getDragEl());
8401 if(this.datatable.fixedWidth) {
8402 var cellLabel = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_LABEL,"span",this.cell)[0];
8403 this.minWidth = cellLabel.offsetWidth + 6;
8404 var sib = this.cell.nextSibling;
8405 var sibCellLabel = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.DataTable.CLASS_LABEL,"span",sib)[0];
8406 this.sibMinWidth = sibCellLabel.offsetWidth + 6;
8408 var left = ((this.startWidth - this.minWidth) < 0) ? 0 : (this.startWidth - this.minWidth);
8409 var right = ((sib.offsetWidth - this.sibMinWidth) < 0) ? 0 : (sib.offsetWidth - this.sibMinWidth);
8410 this.setXConstraint(left, right);
8411 YAHOO.log("cellstartwidth:" + this.startWidth,"time");
8412 YAHOO.log("cellminwidth:" + this.minWidth,"time");
8413 YAHOO.log("sibstartwidth:" + sib.offsetWidth,"time");
8414 YAHOO.log("sibminwidth:" + this.sibMinWidth,"time");
8415 YAHOO.log("l:" + left + " AND r:" + right,"time");
8421 * Handles mouseup events on the Column resizer.
8424 * @param e {string} The mouseup event
8426 YAHOO.util.ColumnResizer.prototype.onMouseUp = function(e) {
8427 //TODO: replace the resizer where it belongs:
8428 var resizeStyle = YAHOO.util.Dom.get(this.handleElId).style;
8429 resizeStyle.left = "auto";
8430 resizeStyle.right = 0;
8431 resizeStyle.marginRight = "-6px";
8432 resizeStyle.width = "6px";
8433 //.yui-dt-headresizer {position:absolute;margin-right:-6px;right:0;bottom:0;width:6px;height:100%;cursor:w-resize;cursor:col-resize;}
8436 //var cells = this.datatable._elTable.tHead.rows[this.datatable._elTable.tHead.rows.length-1].cells;
8437 //for(var i=0; i<cells.length; i++) {
8438 //cells[i].style.width = "5px";
8441 //TODO: set new ColumnSet width values
8442 this.datatable.fireEvent("columnResizeEvent", {column:this.column,target:this.cell});
8446 * Handles drag events on the Column resizer.
8449 * @param e {string} The drag event
8451 YAHOO.util.ColumnResizer.prototype.onDrag = function(e) {
8452 var newPos = YAHOO.util.Dom.getX(this.getDragEl());
8453 //YAHOO.log("newpos:"+newPos,"warn");//YAHOO.util.Event.getPageX(e);
8454 var offsetX = newPos - this.startPos;
8455 //YAHOO.log("offset:"+offsetX,"warn");
8456 //YAHOO.log("startwidth:"+this.startWidth + " and offset:"+offsetX,"warn");
8457 var newWidth = this.startWidth + offsetX;
8458 //YAHOO.log("newwidth:"+newWidth,"warn");
8460 if(newWidth < this.minWidth) {
8461 newWidth = this.minWidth;
8464 // Resize the Column
8465 var oDataTable = this.datatable;
8466 var elCell = this.cell;
8468 //YAHOO.log("newwidth" + newWidth,"warn");
8469 //YAHOO.log(newWidth + " AND "+ elColumn.offsetWidth + " AND " + elColumn.id,"warn");
8471 // Resize the other Columns
8472 if(oDataTable.fixedWidth) {
8473 // Moving right or left?
8474 var sib = elCell.nextSibling;
8475 //var sibIndex = elCell.index + 1;
8476 var sibnewwidth = sib.offsetWidth - offsetX;
8477 if(sibnewwidth < this.sibMinWidth) {
8478 sibnewwidth = this.sibMinWidth;
8481 //TODO: how else to cycle through all the Columns without having to use an index property?
8482 for(var i=0; i<oDataTable._oColumnSet.length; i++) {
8483 //if((i != elCell.index) && (i!=sibIndex)) {
8484 // YAHOO.util.Dom.get(oDataTable._oColumnSet.keys[i].id).style.width = oDataTable._oColumnSet.keys[i].width + "px";
8487 sib.style.width = sibnewwidth;
8488 elCell.style.width = newWidth + "px";
8489 //oDataTable._oColumnSet.flat[sibIndex].width = sibnewwidth;
8490 //oDataTable._oColumnSet.flat[elCell.index].width = newWidth;
8494 elCell.style.width = newWidth + "px";
8501 /****************************************************************************/
8502 /****************************************************************************/
8503 /****************************************************************************/
8506 * A RecordSet defines and manages a set of Records.
8508 * @namespace YAHOO.widget
8510 * @param data {Object || Object[]} An object literal or an array of data.
8513 YAHOO.widget.RecordSet = function(data) {
8514 // Internal variables
8515 this._sName = "RecordSet instance" + YAHOO.widget.RecordSet._nCount;
8516 YAHOO.widget.RecordSet._nCount++;
8521 if(YAHOO.lang.isArray(data)) {
8522 this.addRecords(data);
8524 else if(data.constructor == Object) {
8525 this.addRecord(data);
8530 * Fired when a new Record is added to the RecordSet.
8532 * @event recordAddEvent
8533 * @param oArgs.record {YAHOO.widget.Record} The Record instance.
8534 * @param oArgs.data {Object} Data added.
8536 this.createEvent("recordAddEvent");
8539 * Fired when multiple Records are added to the RecordSet at once.
8541 * @event recordsAddEvent
8542 * @param oArgs.records {YAHOO.widget.Record[]} An array of Record instances.
8543 * @param oArgs.data {Object[]} Data added.
8545 this.createEvent("recordsAddEvent");
8548 * Fired when a Record is updated with new data.
8550 * @event recordUpdateEvent
8551 * @param oArgs.record {YAHOO.widget.Record} The Record instance.
8552 * @param oArgs.newData {Object} New data.
8553 * @param oArgs.oldData {Object} Old data.
8555 this.createEvent("recordUpdateEvent");
8558 * Fired when a Record is deleted from the RecordSet.
8560 * @event recordDeleteEvent
8561 * @param oArgs.data {Object} A copy of the data held by the Record,
8562 * or an array of data object literals if multiple Records were deleted at once.
8563 * @param oArgs.index {Object} Index of the deleted Record.
8565 this.createEvent("recordDeleteEvent");
8568 * Fired when multiple Records are deleted from the RecordSet at once.
8570 * @event recordsDeleteEvent
8571 * @param oArgs.data {Object[]} An array of data object literals copied
8573 * @param oArgs.index {Object} Index of the first deleted Record.
8575 this.createEvent("recordsDeleteEvent");
8578 * Fired when all Records are deleted from the RecordSet at once.
8582 this.createEvent("resetEvent");
8585 * Fired when a Record Key is updated with new data.
8587 * @event keyUpdateEvent
8588 * @param oArgs.record {YAHOO.widget.Record} The Record instance.
8589 * @param oArgs.key {String} The updated key.
8590 * @param oArgs.newData {Object} New data.
8591 * @param oArgs.oldData {Object} Old data.
8594 this.createEvent("keyUpdateEvent");
8596 YAHOO.log("RecordSet initialized", "info", this.toString());
8599 if(YAHOO.util.EventProvider) {
8600 YAHOO.augment(YAHOO.widget.RecordSet, YAHOO.util.EventProvider);
8603 YAHOO.log("Missing dependency: YAHOO.util.EventProvider","error",this.toString());
8606 /////////////////////////////////////////////////////////////////////////////
8608 // Private member variables
8610 /////////////////////////////////////////////////////////////////////////////
8612 * Internal class variable to name multiple Recordset instances.
8614 * @property RecordSet._nCount
8619 YAHOO.widget.RecordSet._nCount = 0;
8622 * Unique instance name.
8628 YAHOO.widget.RecordSet.prototype._sName = null;
8631 * Internal variable to give unique indexes to Record instances.
8637 YAHOO.widget.RecordSet.prototype._nRecordCount = 0;
8640 * Internal counter of how many Records are in the RecordSet.
8646 YAHOO.widget.RecordSet.prototype._length = null;
8648 /////////////////////////////////////////////////////////////////////////////
8652 /////////////////////////////////////////////////////////////////////////////
8655 * Adds one Record to the RecordSet at the given index. If index is null,
8656 * then adds the Record to the end of the RecordSet.
8658 * @method _addRecord
8659 * @param oData {Object} An object literal of data.
8660 * @param index {Number} (optional) Position index.
8661 * @return {YAHOO.widget.Record} A Record instance.
8664 YAHOO.widget.RecordSet.prototype._addRecord = function(oData, index) {
8665 var oRecord = new YAHOO.widget.Record(oData);
8666 oRecord._nId = this._nRecordCount;
8667 this._nRecordCount++;
8669 if(YAHOO.lang.isNumber(index) && (index > -1)) {
8670 this._records.splice(index,0,oRecord);
8673 index = this.getLength();
8674 this._records.push(oRecord);
8681 * Deletes Records from the RecordSet at the given index. If range is null,
8682 * then only one Record is deleted.
8684 * @method _deleteRecord
8685 * @param index {Number} Position index.
8686 * @param range {Number} (optional) How many Records to delete
8689 YAHOO.widget.RecordSet.prototype._deleteRecord = function(index, range) {
8690 if(!YAHOO.lang.isNumber(range) || (range < 0)) {
8693 this._records.splice(index, range);
8694 this._length = this._length - range;
8697 /////////////////////////////////////////////////////////////////////////////
8701 /////////////////////////////////////////////////////////////////////////////
8704 * Public accessor to the unique name of the RecordSet instance.
8707 * @return {String} Unique name of the RecordSet instance.
8709 YAHOO.widget.RecordSet.prototype.toString = function() {
8714 * Returns the number of Records held in the RecordSet.
8717 * @return {Number} Number of records in the RecordSet.
8719 YAHOO.widget.RecordSet.prototype.getLength = function() {
8720 return this._length;
8724 * Returns Record at given position index.
8727 * @param index {Number} Record's Recordset position index.
8728 * @return {YAHOO.widget.Record} Record object.
8730 YAHOO.widget.RecordSet.prototype.getRecord = function(index) {
8731 if(YAHOO.lang.isNumber(index)) {
8732 return this._records[index];
8734 /*else if(YAHOO.lang.isString(identifier)) {
8735 for(var i=0; i<this._records.length; i++) {
8736 if(this._records[i].yuiRecordId == identifier) {
8737 return this._records[i];
8746 * Returns an array of Records from the RecordSet.
8748 * @method getRecords
8749 * @param index {Number} (optional) Recordset position index of which Record to
8751 * @param range {Number} (optional) Number of Records to get.
8752 * @return {YAHOO.widget.Record[]} Array of Records starting at given index and
8753 * length equal to given range. If index is not given, all Records are returned.
8755 YAHOO.widget.RecordSet.prototype.getRecords = function(index, range) {
8756 if(!YAHOO.lang.isNumber(index)) {
8757 return this._records;
8759 if(!YAHOO.lang.isNumber(range)) {
8760 return this._records.slice(index);
8762 return this._records.slice(index, index+range);
8766 * Returns position index for the given Record.
8768 * @method getRecordIndex
8769 * @param oRecord {YAHOO.widget.Record} Record instance.
8770 * @return {Number} Record's RecordSet position index.
8773 YAHOO.widget.RecordSet.prototype.getRecordIndex = function(oRecord) {
8774 for(var i=this._records.length-1; i>-1; i--) {
8775 if(oRecord.getId() === this._records[i].getId()) {
8784 * Adds one Record to the RecordSet at the given index. If index is null,
8785 * then adds the Record to the end of the RecordSet.
8788 * @param oData {Object} An object literal of data.
8789 * @param index {Number} (optional) Position index.
8790 * @return {YAHOO.widget.Record} A Record instance.
8792 YAHOO.widget.RecordSet.prototype.addRecord = function(oData, index) {
8793 if(oData && (oData.constructor == Object)) {
8794 var oRecord = this._addRecord(oData, index);
8795 this.fireEvent("recordAddEvent",{record:oRecord,data:oData});
8796 YAHOO.log("Added Record at index " + index +
8797 " with data " + YAHOO.lang.dump(oData), "info", this.toString());
8801 YAHOO.log("Could not add Record with data" +
8802 YAHOO.lang.dump(oData), "info", this.toString());
8808 * Adds multiple Records at once to the RecordSet at the given index with the
8809 * given data. If index is null, then the new Records are added to the end of
8812 * @method addRecords
8813 * @param aData {Object[]} An array of object literal data.
8814 * @param index {Number} (optional) Position index.
8815 * @return {YAHOO.widget.Record[]} An array of Record instances.
8817 YAHOO.widget.RecordSet.prototype.addRecords = function(aData, index) {
8818 if(YAHOO.lang.isArray(aData)) {
8819 var newRecords = [];
8820 // Can't go backwards bc we need to preserve order
8821 for(var i=0; i<aData.length; i++) {
8822 if(aData[i] && (aData[i].constructor == Object)) {
8823 var record = this._addRecord(aData[i], index);
8824 newRecords.push(record);
8827 this.fireEvent("recordsAddEvent",{records:newRecords,data:aData});
8828 YAHOO.log("Added " + newRecords.length + " Record(s) at index " + index +
8829 " with data " + YAHOO.lang.dump(aData), "info", this.toString());
8832 else if(aData && (aData.constructor == Object)) {
8833 var oRecord = this._addRecord(aData);
8834 this.fireEvent("recordsAddEvent",{records:[oRecord],data:aData});
8835 YAHOO.log("Added 1 Record at index " + index +
8836 " with data " + YAHOO.lang.dump(aData), "info", this.toString());
8840 YAHOO.log("Could not add Records with data " +
8841 YAHOO.lang.dump(aData), "info", this.toString());
8846 * Updates given Record with given data.
8848 * @method updateRecord
8849 * @param record {YAHOO.widget.Record | Number} A Record instance, or Record's
8850 * RecordSet position index.
8851 * @param oData {Object) Object literal of new data.
8852 * @return {YAHOO.widget.Record} Updated Record, or null.
8854 YAHOO.widget.RecordSet.prototype.updateRecord = function(record, oData) {
8856 if(YAHOO.lang.isNumber(record)) {
8857 oRecord = this._records[record];
8859 else if(record instanceof YAHOO.widget.Record) {
8862 if(oRecord && oData && (oData.constructor == Object)) {
8863 // Copy data from the Record for the event that gets fired later
8865 for(var key in oRecord._oData) {
8866 oldData[key] = oRecord._oData[key];
8868 oRecord._oData = oData;
8869 this.fireEvent("recordUpdateEvent",{record:oRecord,newData:oData,oldData:oldData});
8870 YAHOO.log("Record at index " + this.getRecordIndex(oRecord) +
8871 " updated with data " + YAHOO.lang.dump(oData), "info", this.toString());
8875 YAHOO.log("Could not update Record " + record, "error", this.toString());
8881 * Updates given Record at given key with given data.
8884 * @param record {YAHOO.widget.Record | Number} A Record instance, or Record's
8885 * RecordSet position index.
8886 * @param sKey {String} Key name.
8887 * @param oData {Object) New data.
8889 YAHOO.widget.RecordSet.prototype.updateKey = function(record, sKey, oData) {
8892 if(YAHOO.lang.isNumber(record)) {
8893 oRecord = this._records[record];
8895 if(record instanceof YAHOO.widget.Record) {
8899 var keyValue = oRecord._oData[sKey];
8900 // Copy data from the Record for the event that gets fired later
8901 if(keyValue && keyValue.constructor == Object) {
8903 for(var key in keyValue) {
8904 oldData[key] = keyValue[key];
8912 oRecord._oData[sKey] = oData;
8913 this.fireEvent("keyUpdateEvent",{record:oRecord,key:sKey,newData:oData,oldData:oldData});
8914 YAHOO.log("Key \"" + sKey +
8915 "\" for Record at index " + this.getRecordIndex(oRecord) +
8916 " updated to \"" + YAHOO.lang.dump(oData) + "\"", "info", this.toString());
8919 YAHOO.log("Could not update key " + sKey + " for Record " + record, "error", this.toString());
8924 * Replaces all Records in RecordSet with new data.
8926 * @method replaceRecords
8927 * @param data {Object || Object[]} An object literal of data or an array of
8928 * object literal data.
8929 * @return {YAHOO.widget.Record || YAHOO.widget.Record[]} A Record instance or
8930 * an array of Records.
8932 YAHOO.widget.RecordSet.prototype.replaceRecords = function(data) {
8934 return this.addRecords(data);
8938 * Sorts all Records by given function.
8940 * @method sortRecords
8941 * @param fnSort {Function} Reference to a sort function.
8942 * @param desc {Boolean} True if sort direction is descending, false if sort
8943 * direction is ascending.
8944 * @return {YAHOO.widget.Record[]} Sorted array of Records.
8946 YAHOO.widget.RecordSet.prototype.sortRecords = function(fnSort, desc) {
8947 return this._records.sort(function(a, b) {return fnSort(a, b, desc);});
8952 * Removes the Record at the given position index from the RecordSet. If a range
8953 * is also provided, removes that many Records, starting from the index. Length
8954 * of RecordSet is correspondingly shortened.
8956 * @method deleteRecord
8957 * @param index {Number} Record's RecordSet position index.
8958 * @param range {Number} (optional) How many Records to delete.
8959 * @return {Object} A copy of the data held by the deleted Record.
8961 YAHOO.widget.RecordSet.prototype.deleteRecord = function(index) {
8962 if(YAHOO.lang.isNumber(index) && (index > -1) && (index < this.getLength())) {
8963 // Copy data from the Record for the event that gets fired later
8964 var oRecordData = this.getRecord(index).getData();
8966 for(var key in oRecordData) {
8967 oData[key] = oRecordData[key];
8970 this._deleteRecord(index);
8971 this.fireEvent("recordDeleteEvent",{data:oData,index:index});
8972 YAHOO.log("Record deleted at index " + index +
8973 " and containing data " + YAHOO.lang.dump(oData), "info", this.toString());
8977 YAHOO.log("Could not delete Record at index " + index, "error", this.toString());
8983 * Removes the Record at the given position index from the RecordSet. If a range
8984 * is also provided, removes that many Records, starting from the index. Length
8985 * of RecordSet is correspondingly shortened.
8987 * @method deleteRecords
8988 * @param index {Number} Record's RecordSet position index.
8989 * @param range {Number} (optional) How many Records to delete.
8991 YAHOO.widget.RecordSet.prototype.deleteRecords = function(index, range) {
8992 if(!YAHOO.lang.isNumber(range)) {
8995 if(YAHOO.lang.isNumber(index) && (index > -1) && (index < this.getLength())) {
8996 var recordsToDelete = this.getRecords(index, range);
8997 // Copy data from each Record for the event that gets fired later
8998 var deletedData = [];
8999 for(var i=0; i<recordsToDelete.length; i++) {
9001 for(var key in recordsToDelete[i]) {
9002 oData[key] = recordsToDelete[i][key];
9004 deletedData.push(oData);
9006 this._deleteRecord(index, range);
9008 this.fireEvent("recordsDeleteEvent",{data:deletedData,index:index});
9009 YAHOO.log(range + "Record(s) deleted at index " + index +
9010 " and containing data " + YAHOO.lang.dump(deletedData), "info", this.toString());
9014 YAHOO.log("Could not delete Records at index " + index, "error", this.toString());
9019 * Deletes all Records from the RecordSet.
9023 YAHOO.widget.RecordSet.prototype.reset = function() {
9026 this.fireEvent("resetEvent");
9027 YAHOO.log("All Records deleted from RecordSet", "info", this.toString());
9031 /****************************************************************************/
9032 /****************************************************************************/
9033 /****************************************************************************/
9036 * The Record class defines a DataTable record.
9038 * @namespace YAHOO.widget
9041 * @param oConfigs {Object} (optional) Object literal of key/value pairs.
9043 YAHOO.widget.Record = function(oLiteral) {
9045 if(oLiteral && (oLiteral.constructor == Object)) {
9046 for(var sKey in oLiteral) {
9047 this._oData[sKey] = oLiteral[sKey];
9052 /////////////////////////////////////////////////////////////////////////////
9054 // Private member variables
9056 /////////////////////////////////////////////////////////////////////////////
9058 * Unique number assigned at instantiation, indicates original order within
9065 YAHOO.widget.Record.prototype._nId = null;
9068 * Holds data for the Record in an object literal.
9074 YAHOO.widget.Record.prototype._oData = null;
9076 /////////////////////////////////////////////////////////////////////////////
9078 // Public member variables
9080 /////////////////////////////////////////////////////////////////////////////
9082 /////////////////////////////////////////////////////////////////////////////
9086 /////////////////////////////////////////////////////////////////////////////
9089 * Returns unique number assigned at instantiation, indicates original order
9095 YAHOO.widget.Record.prototype.getId = function() {
9100 * Returns data for the Record for a key if given, or the entire object
9101 * literal otherwise.
9104 * @param sKey {String} (Optional) The key to retrieve a single data value.
9107 YAHOO.widget.Record.prototype.getData = function(sKey) {
9108 if(YAHOO.lang.isString(sKey)) {
9109 return this._oData[sKey];
9117 YAHOO.register("datatable", YAHOO.widget.DataTable, {version: "2.3.0", build: "442"});