3
Copyright 2012 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('datatable-base-deprecated', function(Y) {
10
YisValue = YLang.isValue,
11
fromTemplate = Y.Lang.sub,
13
Ycreate = YNode.create,
14
YgetClassName = Y.ClassNameManager.getClassName,
16
DATATABLE = "datatable",
21
MOUSEENTER = "mouseenter",
22
MOUSELEAVE = "mouseleave",
24
MOUSEDOWN = "mousedown",
26
DBLCLICK = "dblclick",
28
CLASS_COLUMNS = YgetClassName(DATATABLE, "columns"),
29
CLASS_DATA = YgetClassName(DATATABLE, "data"),
30
CLASS_MSG = YgetClassName(DATATABLE, "msg"),
31
CLASS_LINER = YgetClassName(DATATABLE, "liner"),
32
CLASS_FIRST = YgetClassName(DATATABLE, "first"),
33
CLASS_LAST = YgetClassName(DATATABLE, "last"),
34
CLASS_EVEN = YgetClassName(DATATABLE, "even"),
35
CLASS_ODD = YgetClassName(DATATABLE, "odd"),
37
TEMPLATE_TABLE = '<table></table>',
38
TEMPLATE_COL = '<col></col>',
39
TEMPLATE_THEAD = '<thead class="'+CLASS_COLUMNS+'"></thead>',
40
TEMPLATE_TBODY = '<tbody class="'+CLASS_DATA+'"></tbody>',
41
TEMPLATE_TH = '<th id="{id}" rowspan="{rowspan}" colspan="{colspan}" class="{classnames}" abbr="{abbr}"><div class="'+CLASS_LINER+'">{value}</div></th>',
42
TEMPLATE_TR = '<tr id="{id}"></tr>',
43
TEMPLATE_TD = '<td headers="{headers}" class="{classnames}"><div class="'+CLASS_LINER+'">{value}</div></td>',
44
TEMPLATE_VALUE = '{value}',
45
TEMPLATE_MSG = '<tbody class="'+CLASS_MSG+'"></tbody>';
50
* The Column class defines and manages attributes of Columns for DataTable.
56
function Column(config) {
57
Column.superclass.constructor.apply(this, arguments);
60
/////////////////////////////////////////////////////////////////////////////
64
/////////////////////////////////////////////////////////////////////////////
77
/////////////////////////////////////////////////////////////////////////////
81
/////////////////////////////////////////////////////////////////////////////
84
Unique internal identifier, used to stamp ID on TH element.
91
valueFn: "_defaultId",
96
User-supplied identifier. Defaults to id.
101
valueFn: "_defaultKey"
105
Points to underlying data field (for sorting or formatting, for
106
example). Useful when column doesn't hold any data itself, but is just
107
a visual representation of data from another column or record field.
112
@default (column key)
115
valueFn: "_defaultField"
119
Display label for column header. Defaults to key.
125
valueFn: "_defaultLabel"
129
Array of child column definitions (for nested headers).
150
//TODO: support custom classnames
154
getter: "_getClassnames"
158
Formating template string or function for cells in this column.
160
Function formatters receive a single object (described below) and are
161
expected to output the `innerHTML` of the cell.
163
String templates can include markup and {placeholder} tokens to be
164
filled in from the object passed to function formatters.
167
@type {String|Function}
168
@param {Object} data Data relevant to the rendering of this cell
169
@param {String} data.classnames CSS classes to add to the cell
170
@param {Column} data.column This Column instance
171
@param {Object} data.data The raw object data from the Record
172
@param {String} data.field This Column's "field" attribute value
173
@param {String} data.headers TH ids to reference in the cell's
175
@param {Record} data.record The Record instance for this row
176
@param {Number} data.rowindex The index for this row
177
@param {Node} data.tbody The TBODY Node that will house the cell
178
@param {Node} data.tr The row TR Node that will house the cell
179
@param {Any} data.value The raw Record data for this cell
184
The default markup to display in cells that have no corresponding record
185
data or content from formatters.
187
@attribute emptyCellValue
193
validator: Y.Lang.isString
196
//requires datatable-sort
200
//sortOptions:defaultDir, sortFn, field
202
//TODO: support editable columns
206
//TODO: support resizeable columns
207
//TODO: support setting widths
208
// requires datatable-colresize
217
/////////////////////////////////////////////////////////////////////////////
221
/////////////////////////////////////////////////////////////////////////////
222
Y.extend(Column, Y.Widget, {
223
/////////////////////////////////////////////////////////////////////////////
227
/////////////////////////////////////////////////////////////////////////////
229
* Return ID for instance.
235
_defaultId: function() {
240
* Return key for instance. Defaults to ID if one was not provided.
242
* @method _defaultKey
246
_defaultKey: function() {
251
* Return field for instance. Defaults to key if one was not provided.
253
* @method _defaultField
257
_defaultField: function() {
258
return this.get("key");
262
* Return label for instance. Defaults to key if one was not provided.
264
* @method _defaultLabel
268
_defaultLabel: function() {
269
return this.get("key");
273
* Updates the UI if changes are made to abbr.
275
* @method _afterAbbrChange
276
* @param e {Event} Custom event for the attribute change.
279
_afterAbbrChange: function (e) {
280
this._uiSetAbbr(e.newVal);
283
/////////////////////////////////////////////////////////////////////////////
287
/////////////////////////////////////////////////////////////////////////////
289
* Reference to Column's current position index within its Columnset's keys
290
* array, if applicable. This property only applies to non-nested and bottom-
291
* level child Columns. Value is set by Columnset code.
299
* Array of TH IDs associated with this column, for TD "headers" attribute.
300
* Value is set by Columnset code
308
* Number of cells the header spans. Value is set by Columnset code.
317
* Number of rows the header spans. Value is set by Columnset code.
326
* Column's parent Column instance, if applicable. Value is set by Columnset
335
* The Node reference to the associated TH element.
344
* The Node reference to the associated liner element.
346
* @property thLinerNode
351
/////////////////////////////////////////////////////////////////////////////
355
/////////////////////////////////////////////////////////////////////////////
359
* @method initializer
360
* @param config {Object} Config object.
363
initializer: function(config) {
372
destructor: function() {
376
* Returns classnames for Column.
378
* @method _getClassnames
381
_getClassnames: function () {
382
return Y.ClassNameManager.getClassName(COLUMN, this.get("key").replace(/[^\w\-]/g,""));
385
////////////////////////////////////////////////////////////////////////////
389
////////////////////////////////////////////////////////////////////////////
391
* Syncs UI to intial state.
397
this._uiSetAbbr(this.get("abbr"));
404
* @param val {String} New abbr.
407
_uiSetAbbr: function(val) {
408
this.thNode.set("abbr", val);
414
* The Columnset class defines and manages a collection of Columns.
420
function Columnset(config) {
421
Columnset.superclass.constructor.apply(this, arguments);
424
/////////////////////////////////////////////////////////////////////////////
428
/////////////////////////////////////////////////////////////////////////////
441
/////////////////////////////////////////////////////////////////////////////
445
/////////////////////////////////////////////////////////////////////////////
448
* @attribute definitions
449
* @description Array of column definitions that will populate this Columnset.
453
setter: "_setDefinitions"
459
/////////////////////////////////////////////////////////////////////////////
463
/////////////////////////////////////////////////////////////////////////////
464
Y.extend(Columnset, Y.Base, {
465
/////////////////////////////////////////////////////////////////////////////
469
/////////////////////////////////////////////////////////////////////////////
471
* @method _setDefinitions
472
* @description Clones definitions before setting.
473
* @param definitions {Array} Array of column definitions.
477
_setDefinitions: function(definitions) {
478
return Y.clone(definitions);
481
/////////////////////////////////////////////////////////////////////////////
485
/////////////////////////////////////////////////////////////////////////////
487
* Top-down tree representation of Column hierarchy. Used to create DOM
496
* Hash of all Columns by ID.
504
* Hash of all Columns by key.
512
* Array of only Columns that are meant to be displayed in DOM.
519
/////////////////////////////////////////////////////////////////////////////
523
/////////////////////////////////////////////////////////////////////////////
525
* Initializer. Generates all internal representations of the collection of
528
* @method initializer
529
* @param config {Object} Config object.
532
initializer: function() {
534
// DOM tree representation of all Columns
536
// Hash of all Columns by ID
538
// Hash of all Columns by key
540
// Flat representation of only Columns that are meant to display data
542
// Original definitions
543
definitions = this.get("definitions"),
547
// Internal recursive function to define Column instances
548
function parseColumns(depth, currentDefinitions, parent) {
550
len = currentDefinitions.length,
558
// Create corresponding dom node if not already there for this depth
563
// Parse each node at this depth for attributes and any children
565
currentDefinition = currentDefinitions[i];
567
currentDefinition = YLang.isString(currentDefinition) ? {key:currentDefinition} : currentDefinition;
569
// Instantiate a new Column for each node
570
column = new Y.Column(currentDefinition);
572
// Cross-reference Column ID back to the original object literal definition
573
currentDefinition.yuiColumnId = column.get("id");
575
// Add the new Column to the hash
576
idHash[column.get("id")] = column;
577
keyHash[column.get("key")] = column;
579
// Assign its parent as an attribute, if applicable
581
column.parent = parent;
584
// The Column has descendants
585
if(YLang.isArray(currentDefinition.children)) {
586
currentChildren = currentDefinition.children;
587
column._set("children", currentChildren);
589
self._setColSpans(column, currentDefinition);
591
self._cascadePropertiesToChildren(column, currentChildren);
593
// The children themselves must also be parsed for Column instances
597
parseColumns(depth, currentChildren, column);
599
// This Column does not have any children
601
column.keyIndex = keys.length;
602
// Default is already 1
603
//column.colSpan = 1;
607
// Add the Column to the top-down dom tree
608
tree[depth].push(column);
613
// Parse out Column instances from the array of object literals
614
parseColumns(-1, definitions);
617
// Save to the Columnset instance
619
this.idHash = idHash;
620
this.keyHash = keyHash;
633
destructor: function() {
636
/////////////////////////////////////////////////////////////////////////////
640
/////////////////////////////////////////////////////////////////////////////
642
* Cascade certain properties to children if not defined on their own.
644
* @method _cascadePropertiesToChildren
647
_cascadePropertiesToChildren: function(column, currentChildren) {
648
//TODO: this is all a giant todo
650
len = currentChildren.length,
653
// Cascade certain properties to children if not defined on their own
655
child = currentChildren[i];
656
if(column.get("className") && (child.className === undefined)) {
657
child.className = column.get("className");
659
if(column.get("editor") && (child.editor === undefined)) {
660
child.editor = column.get("editor");
662
if(column.get("formatter") && (child.formatter === undefined)) {
663
child.formatter = column.get("formatter");
665
if(column.get("resizeable") && (child.resizeable === undefined)) {
666
child.resizeable = column.get("resizeable");
668
if(column.get("sortable") && (child.sortable === undefined)) {
669
child.sortable = column.get("sortable");
671
if(column.get("hidden")) {
674
if(column.get("width") && (child.width === undefined)) {
675
child.width = column.get("width");
677
if(column.get("minWidth") && (child.minWidth === undefined)) {
678
child.minWidth = column.get("minWidth");
680
if(column.get("maxAutoWidth") && (child.maxAutoWidth === undefined)) {
681
child.maxAutoWidth = column.get("maxAutoWidth");
687
* @method _setColSpans
688
* @description Calculates and sets colSpan attribute on given Column.
689
* @param column {Array} Column instance.
690
* @param definition {Object} Column definition.
693
_setColSpans: function(column, definition) {
694
// Determine COLSPAN value for this Column
695
var terminalChildNodes = 0;
697
function countTerminalChildNodes(ancestor) {
698
var descendants = ancestor.children,
700
len = descendants.length;
702
// Drill down each branch and count terminal nodes
704
// Keep drilling down
705
if(YLang.isArray(descendants[i].children)) {
706
countTerminalChildNodes(descendants[i]);
708
// Reached branch terminus
710
terminalChildNodes++;
714
countTerminalChildNodes(definition);
715
column.colSpan = terminalChildNodes;
719
* @method _setRowSpans
720
* @description Calculates and sets rowSpan attribute on all Columns.
723
_setRowSpans: function() {
724
// Determine ROWSPAN value for each Column in the DOM tree
725
function parseDomTreeForRowSpan(tree) {
731
// Calculate the max depth of descendants for this row
732
function countMaxRowDepth(row, tmpRowDepth) {
733
tmpRowDepth = tmpRowDepth || 1;
741
// Column has children, so keep counting
742
if(YLang.isArray(col.children)) {
744
countMaxRowDepth(col.children, tmpRowDepth);
747
// Column has children, so keep counting
748
else if(col.get && YLang.isArray(col.get("children"))) {
750
countMaxRowDepth(col.get("children"), tmpRowDepth);
753
// No children, is it the max depth?
755
if(tmpRowDepth > maxRowDepth) {
756
maxRowDepth = tmpRowDepth;
762
// Count max row depth for each row
763
for(m=0; m<tree.length; m++) {
764
currentRow = tree[m];
765
countMaxRowDepth(currentRow);
767
// Assign the right ROWSPAN values to each Column in the row
768
for(p=0; p<currentRow.length; p++) {
769
currentColumn = currentRow[p];
770
if(!YLang.isArray(currentColumn.get("children"))) {
771
currentColumn.rowSpan = maxRowDepth;
773
// Default is already 1
774
// else currentColumn.rowSpan =1;
777
// Reset counter for next row
781
parseDomTreeForRowSpan(this.tree);
785
* @method _setHeaders
786
* @description Calculates and sets headers attribute on all Columns.
789
_setHeaders: function() {
792
i=0, len = allKeys.length;
794
function recurseAncestorsForHeaders(headers, column) {
795
headers.push(column.get("id"));
797
recurseAncestorsForHeaders(headers, column.parent);
803
recurseAncestorsForHeaders(headers, column);
804
column.headers = headers.reverse().join(" ");
809
getColumn: function() {
813
Y.Columnset = Columnset;
815
* The DataTable widget provides a progressively enhanced DHTML control for
816
* displaying tabular data across A-grade browsers.
823
* Provides the base DataTable implementation, which can be extended to add
824
* additional functionality, such as sorting or scrolling.
827
* @submodule datatable-base
831
* Base class for the DataTable widget.
832
* @class DataTable.Base
836
function DTBase(config) {
837
DTBase.superclass.constructor.apply(this, arguments);
840
/////////////////////////////////////////////////////////////////////////////
844
/////////////////////////////////////////////////////////////////////////////
858
/////////////////////////////////////////////////////////////////////////////
862
/////////////////////////////////////////////////////////////////////////////
865
* @attribute columnset
866
* @description Pointer to Columnset instance.
867
* @type Array | Y.Columnset
870
setter: "_setColumnset"
874
* @attribute recordset
875
* @description Pointer to Recordset instance.
876
* @type Array | Y.Recordset
879
valueFn: '_initRecordset',
880
setter: "_setRecordset"
885
* @description Internal state.
890
value: new Y.State(),
897
* @description Summary.
905
* @description Caption
912
* @attribute thValueTemplate
913
* @description Tokenized markup template for TH value.
918
value: TEMPLATE_VALUE
922
* @attribute tdValueTemplate
923
* @description Tokenized markup template for TD value.
928
value: TEMPLATE_VALUE
932
* @attribute trTemplate
933
* @description Tokenized markup template for TR node creation.
935
* @default '<tr id="{id}"></tr>'
942
/////////////////////////////////////////////////////////////////////////////
946
/////////////////////////////////////////////////////////////////////////////
948
/*caption: function (srcNode) {
954
/////////////////////////////////////////////////////////////////////////////
958
/////////////////////////////////////////////////////////////////////////////
959
Y.extend(DTBase, Y.Widget, {
961
* @property thTemplate
962
* @description Tokenized markup template for TH node creation.
964
* @default '<th id="{id}" rowspan="{rowspan}" colspan="{colspan}" class="{classnames}" abbr="{abbr}"><div class="'+CLASS_LINER+'">{value}</div></th>'
966
thTemplate: TEMPLATE_TH,
969
* @property tdTemplate
970
* @description Tokenized markup template for TD node creation.
972
* @default '<td headers="{headers}" class="{classnames}"><div class="yui3-datatable-liner">{value}</div></td>'
974
tdTemplate: TEMPLATE_TD,
977
* @property _theadNode
978
* @description Pointer to THEAD node.
985
* @property _tbodyNode
986
* @description Pointer to TBODY node.
994
* @description Pointer to message display node.
1000
/////////////////////////////////////////////////////////////////////////////
1002
// ATTRIBUTE HELPERS
1004
/////////////////////////////////////////////////////////////////////////////
1006
* @method _setColumnset
1007
* @description Converts Array to Y.Columnset.
1008
* @param columns {Array | Y.Columnset}
1009
* @return {Columnset}
1012
_setColumnset: function(columns) {
1013
return YLang.isArray(columns) ? new Y.Columnset({definitions:columns}) : columns;
1017
* Updates the UI if Columnset is changed.
1019
* @method _afterColumnsetChange
1020
* @param e {Event} Custom event for the attribute change.
1023
_afterColumnsetChange: function (e) {
1024
this._uiSetColumnset(e.newVal);
1028
* @method _setRecordset
1029
* @description Converts Array to Y.Recordset.
1030
* @param records {Array | Recordset}
1031
* @return {Recordset}
1034
_setRecordset: function(rs) {
1035
if(YLang.isArray(rs)) {
1036
rs = new Y.Recordset({records:rs});
1044
* Updates the UI if Recordset is changed.
1046
* @method _afterRecordsetChange
1047
* @param e {Event} Custom event for the attribute change.
1050
_afterRecordsetChange: function (e) {
1051
this._uiSetRecordset(e.newVal);
1055
* Updates the UI if Recordset records are changed.
1057
* @method _afterRecordsChange
1058
* @param e {Event} Custom event for the attribute change.
1061
_afterRecordsChange: function (e) {
1062
this._uiSetRecordset(this.get('recordset'));
1066
* Updates the UI if summary is changed.
1068
* @method _afterSummaryChange
1069
* @param e {Event} Custom event for the attribute change.
1072
_afterSummaryChange: function (e) {
1073
this._uiSetSummary(e.newVal);
1077
* Updates the UI if caption is changed.
1079
* @method _afterCaptionChange
1080
* @param e {Event} Custom event for the attribute change.
1083
_afterCaptionChange: function (e) {
1084
this._uiSetCaption(e.newVal);
1087
////////////////////////////////////////////////////////////////////////////
1091
////////////////////////////////////////////////////////////////////////////
1096
* @method destructor
1099
destructor: function() {
1100
this.get("recordset").removeTarget(this);
1103
////////////////////////////////////////////////////////////////////////////
1107
////////////////////////////////////////////////////////////////////////////
1115
renderUI: function() {
1117
this._addTableNode(this.get("contentBox"));
1120
this._addColgroupNode(this._tableNode);
1123
this._addTheadNode(this._tableNode);
1126
this._addTbodyNode(this._tableNode);
1129
this._addMessageNode(this._tableNode);
1132
this._addCaptionNode(this._tableNode);
1136
* Creates and attaches TABLE element to given container.
1138
* @method _addTableNode
1139
* @param containerNode {Node} Parent node.
1143
_addTableNode: function(containerNode) {
1144
if (!this._tableNode) {
1145
this._tableNode = containerNode.appendChild(Ycreate(TEMPLATE_TABLE));
1147
return this._tableNode;
1151
* Creates and attaches COLGROUP element to given TABLE.
1153
* @method _addColgroupNode
1154
* @param tableNode {Node} Parent node.
1158
_addColgroupNode: function(tableNode) {
1159
// Add COLs to DOCUMENT FRAGMENT
1160
var len = this.get("columnset").keys.length,
1162
allCols = ["<colgroup>"];
1165
allCols.push(TEMPLATE_COL);
1168
allCols.push("</colgroup>");
1171
this._colgroupNode = tableNode.insertBefore(Ycreate(allCols.join("")), tableNode.get("firstChild"));
1173
return this._colgroupNode;
1177
* Creates and attaches THEAD element to given container.
1179
* @method _addTheadNode
1180
* @param tableNode {Node} Parent node.
1184
_addTheadNode: function(tableNode) {
1186
this._theadNode = tableNode.insertBefore(Ycreate(TEMPLATE_THEAD), this._colgroupNode.next());
1187
return this._theadNode;
1192
* Creates and attaches TBODY element to given container.
1194
* @method _addTbodyNode
1195
* @param tableNode {Node} Parent node.
1199
_addTbodyNode: function(tableNode) {
1200
this._tbodyNode = tableNode.appendChild(Ycreate(TEMPLATE_TBODY));
1201
return this._tbodyNode;
1205
* Creates and attaches message display element to given container.
1207
* @method _addMessageNode
1208
* @param tableNode {Node} Parent node.
1212
_addMessageNode: function(tableNode) {
1213
this._msgNode = tableNode.insertBefore(Ycreate(TEMPLATE_MSG), this._tbodyNode);
1214
return this._msgNode;
1218
* Creates and attaches CAPTION element to given container.
1220
* @method _addCaptionNode
1221
* @param tableNode {Node} Parent node.
1225
_addCaptionNode: function(tableNode) {
1226
this._captionNode = Y.Node.create('<caption></caption>');
1229
////////////////////////////////////////////////////////////////////////////
1233
////////////////////////////////////////////////////////////////////////////
1241
bindUI: function() {
1243
columnsetChange: this._afterColumnsetChange,
1244
summaryChange : this._afterSummaryChange,
1245
captionChange : this._afterCaptionChange,
1246
recordsetChange: this._afterRecordsChange,
1247
"recordset:tableChange": this._afterRecordsChange
1251
delegate: function(type) {
1252
//TODO: is this necessary?
1253
if(type==="dblclick") {
1254
this.get("boundingBox").delegate.apply(this.get("boundingBox"), arguments);
1257
this.get("contentBox").delegate.apply(this.get("contentBox"), arguments);
1262
////////////////////////////////////////////////////////////////////////////
1266
////////////////////////////////////////////////////////////////////////////
1269
* Syncs UI to intial state.
1274
syncUI: function() {
1276
this._uiSetColumnset(this.get("columnset"));
1278
this._uiSetRecordset(this.get("recordset"));
1280
this._uiSetSummary(this.get("summary"));
1282
this._uiSetCaption(this.get("caption"));
1288
* @method _uiSetSummary
1289
* @param val {String} New summary.
1292
_uiSetSummary: function(val) {
1293
val = YisValue(val) ? val : "";
1294
this._tableNode.set("summary", val);
1300
* @method _uiSetCaption
1301
* @param val {String} New caption.
1304
_uiSetCaption: function(val) {
1305
var caption = this._captionNode,
1306
inDoc = caption.inDoc(),
1307
method = val ? (!inDoc && 'prepend') : (inDoc && 'removeChild');
1309
caption.setContent(val || '');
1312
// prepend of remove necessary
1313
this._tableNode[method](caption);
1318
////////////////////////////////////////////////////////////////////////////
1320
// THEAD/COLUMNSET FUNCTIONALITY
1322
////////////////////////////////////////////////////////////////////////////
1326
* @method _uiSetColumnset
1327
* @param cs {Columnset} New Columnset.
1330
_uiSetColumnset: function(cs) {
1332
thead = this._theadNode,
1335
parent = thead.get("parentNode"),
1336
nextSibling = thead.next();
1338
// Move THEAD off DOM
1341
thead.get("children").remove(true);
1343
// Iterate tree of columns to add THEAD rows
1345
this._addTheadTrNode({
1348
id : '' // to avoid {id} leftovers from the trTemplate
1349
}, (i === 0), (i === len - 1));
1352
// Column helpers needs _theadNode to exist
1353
//this._createColumnHelpers();
1356
// Re-attach THEAD to DOM
1357
parent.insert(thead, nextSibling);
1362
* Creates and attaches header row element.
1364
* @method _addTheadTrNode
1365
* @param o {Object} {thead, columns}.
1366
* @param isFirst {Boolean} Is first row.
1367
* @param isFirst {Boolean} Is last row.
1370
_addTheadTrNode: function(o, isFirst, isLast) {
1371
o.tr = this._createTheadTrNode(o, isFirst, isLast);
1372
this._attachTheadTrNode(o);
1377
* Creates header row element.
1379
* @method _createTheadTrNode
1380
* @param o {Object} {thead, columns}.
1381
* @param isFirst {Boolean} Is first row.
1382
* @param isLast {Boolean} Is last row.
1386
_createTheadTrNode: function(o, isFirst, isLast) {
1387
//TODO: custom classnames
1388
var tr = Ycreate(fromTemplate(this.get("trTemplate"), o)),
1390
columns = o.columns,
1391
len = columns.length,
1394
// Set FIRST/LAST class
1396
tr.addClass(CLASS_FIRST);
1399
tr.addClass(CLASS_LAST);
1403
column = columns[i];
1404
this._addTheadThNode({value:column.get("label"), column: column, tr:tr});
1411
* Attaches header row element.
1413
* @method _attachTheadTrNode
1414
* @param o {Object} {thead, columns, tr}.
1417
_attachTheadTrNode: function(o) {
1418
o.thead.appendChild(o.tr);
1422
* Creates and attaches header cell element.
1424
* @method _addTheadThNode
1425
* @param o {Object} {value, column, tr}.
1428
_addTheadThNode: function(o) {
1429
o.th = this._createTheadThNode(o);
1430
this._attachTheadThNode(o);
1431
//TODO: assign all node pointers: thNode, thLinerNode, thLabelNode
1432
o.column.thNode = o.th;
1436
* Creates header cell element.
1438
* @method _createTheadThNode
1439
* @param o {Object} {value, column, tr}.
1443
_createTheadThNode: function(o) {
1444
var column = o.column;
1446
// Populate template object
1447
o.id = column.get("id");//TODO: validate 1 column ID per document
1448
o.colspan = column.colSpan;
1449
o.rowspan = column.rowSpan;
1450
o.abbr = column.get("abbr");
1451
o.classnames = column.get("classnames");
1452
o.value = fromTemplate(this.get("thValueTemplate"), o);
1455
// Clear minWidth on hidden Columns
1456
if(column.get("hidden")) {
1457
//this._clearMinWidth(column);
1461
return Ycreate(fromTemplate(this.thTemplate, o));
1465
* Attaches header cell element.
1467
* @method _attachTheadThNode
1468
* @param o {Object} {value, column, tr}.
1471
_attachTheadThNode: function(o) {
1472
o.tr.appendChild(o.th);
1475
////////////////////////////////////////////////////////////////////////////
1477
// TBODY/RECORDSET FUNCTIONALITY
1479
////////////////////////////////////////////////////////////////////////////
1483
* @method _uiSetRecordset
1484
* @param rs {Recordset} New Recordset.
1487
_uiSetRecordset: function(rs) {
1489
oldTbody = this._tbodyNode,
1490
parent = oldTbody.get("parentNode"),
1491
nextSibling = oldTbody.next(),
1492
columns = this.get('columnset').keys,
1493
cellValueTemplate = this.get('tdValueTemplate'),
1495
newTbody, i, len, column, formatter;
1497
// Replace TBODY with a new one
1498
//TODO: split _addTbodyNode into create/attach
1501
newTbody = this._addTbodyNode(this._tableNode);
1503
this._tbodyNode = newTbody;
1506
o.rowTemplate = this.get('trTemplate');
1509
// Build up column data to avoid passing through Attribute APIs inside
1510
// render loops for rows and cells
1511
for (i = columns.length - 1; i >= 0; --i) {
1512
column = columns[i];
1515
fields : column.get('field'),
1516
classnames : column.get('classnames'),
1517
emptyCellValue: column.get('emptyCellValue')
1520
formatter = column.get('formatter');
1522
if (YLang.isFunction(formatter)) {
1523
// function formatters need to run before checking if the value
1524
// needs defaulting from column.emptyCellValue
1525
formatter = Y.bind(this._functionFormatter, this, formatter);
1527
if (!YLang.isString(formatter)) {
1528
formatter = cellValueTemplate;
1531
// string formatters need the value defaulted before processing
1532
formatter = Y.bind(this._templateFormatter, this, formatter);
1535
o.columns[i].formatter = formatter;
1539
// Iterate Recordset to use existing TR when possible or add new TR
1540
// TODO i = this.get("state.offsetIndex")
1541
// TODO len =this.get("state.pageLength")
1542
for (i = 0, len = rs.size(); i < len; ++i) {
1543
o.record = rs.item(i);
1544
o.data = o.record.get("data");
1546
this._addTbodyTrNode(o); //TODO: sometimes rowindex != recordindex
1550
parent.insert(this._tbodyNode, nextSibling);
1553
_functionFormatter: function (formatter, o) {
1554
var value = formatter.call(this, o);
1556
return (value !== undefined) ? value : o.emptyCellValue;
1559
_templateFormatter: function (template, o) {
1560
if (o.value === undefined) {
1561
o.value = o.emptyCellValue;
1564
return fromTemplate(template, o);
1568
* Creates and attaches data row element.
1570
* @method _addTbodyTrNode
1571
* @param o {Object} {tbody, record}
1574
_addTbodyTrNode: function(o) {
1575
var row = o.tbody.one("#" + o.record.get("id"));
1577
o.tr = row || this._createTbodyTrNode(o);
1579
this._attachTbodyTrNode(o);
1583
* Creates data row element.
1585
* @method _createTbodyTrNode
1586
* @param o {Object} {tbody, record}
1590
_createTbodyTrNode: function(o) {
1591
var columns = o.columns,
1594
o.tr = Ycreate(fromTemplate(o.rowTemplate, { id: o.record.get('id') }));
1596
for (i = 0, len = columns.length; i < len; ++i) {
1597
columnInfo = columns[i];
1598
o.column = columnInfo.column;
1599
o.field = columnInfo.fields;
1600
o.classnames = columnInfo.classnames;
1601
o.formatter = columnInfo.formatter;
1602
o.emptyCellValue= columnInfo.emptyCellValue;
1604
this._addTbodyTdNode(o);
1611
* Attaches data row element.
1613
* @method _attachTbodyTrNode
1614
* @param o {Object} {tbody, record, tr}.
1617
_attachTbodyTrNode: function(o) {
1618
var tbody = o.tbody,
1621
nextSibling = tbody.get("children").item(index) || null,
1622
isOdd = (index % 2);
1625
tr.replaceClass(CLASS_EVEN, CLASS_ODD);
1627
tr.replaceClass(CLASS_ODD, CLASS_EVEN);
1630
tbody.insertBefore(tr, nextSibling);
1634
* Creates and attaches data cell element.
1636
* @method _addTbodyTdNode
1637
* @param o {Object} {record, column, tr}.
1640
_addTbodyTdNode: function(o) {
1641
o.td = this._createTbodyTdNode(o);
1642
this._attachTbodyTdNode(o);
1647
Creates a TD Node from the tdTemplate property using the input object as
1648
template {placeholder} values. The created Node is also assigned to the
1649
`td` property on the input object.
1651
If the input object already has a `td` property, it is returned an no new
1655
@param {Object} data Template values
1658
createCell: function (data) {
1659
return data && (data.td ||
1660
(data.td = Ycreate(fromTemplate(this.tdTemplate, data))));
1664
* Creates data cell element.
1666
* @method _createTbodyTdNode
1667
* @param o {Object} {record, column, tr}.
1671
_createTbodyTdNode: function(o) {
1672
o.headers = o.column.headers;
1673
o.value = this.formatDataCell(o);
1675
return o.td || this.createCell(o);
1679
* Attaches data cell element.
1681
* @method _attachTbodyTdNode
1682
* @param o {Object} {record, column, tr, headers, classnames, value}.
1685
_attachTbodyTdNode: function(o) {
1686
o.tr.appendChild(o.td);
1690
* Returns markup to insert into data cell element.
1692
* @method formatDataCell
1693
* @param @param o {Object} {record, column, tr, headers, classnames}.
1695
formatDataCell: function (o) {
1696
o.value = o.data[o.field];
1698
return o.formatter.call(this, o);
1701
_initRecordset: function () {
1702
return new Y.Recordset({ records: [] });
1706
Y.namespace("DataTable").Base = DTBase;
1709
}, '3.5.0' ,{requires:['recordset-base','widget','substitute','event-mouseenter']});