core.js revision fe8924d7ce76cee0e6f7d747517100273513408e
columns: {
// TODO: change to setter to coerce Columnset?
getter: '_getColumns'
},
recordType: {
validator: '_validateRecordType',
writeOnce: true
},
data: {
value : [],
setter: '_setData',
getter: '_getData'
},
headerView: {
validator: '_validateView',
writeOnce: true
},
footerView: {
validator: '_validateView',
writeOnce: true
},
bodyView: {
validator: '_validateView',
writeOnce: true
},
summary: {
value: '',
// For paranoid reasons, the value is escaped on its way in because
// rendering can be based on string concatenation.
},
/**
HTML content of an optional `<caption>` element to appear above the table.
Leave this config unset or set to a falsy value to remove the caption.
@attribute caption
@type HTML
@default '' (empty string)
**/
caption: {
value: ''
},
recordset: {
// TODO: back compat pass through to ML
},
columnset: {
// TODO: back compat pass through to columns
}
};
// -- Instance properties -------------------------------------------------
TABLE_TEMPLATE : '<table></table>',
CAPTION_TEMPLATE: '<caption></caption>',
// -- Public methods ------------------------------------------------------
bindUI: function () {
// TODO: handle widget attribute changes
this.after({
captionChange: this._afterCaptionChange,
});
},
},
},
},
initializer: function (config) {
this._initColumns();
this._initRecordType();
this._initData();
},
renderUI: function () {
this._renderTable();
this._renderHeader();
this._renderFooter();
this._renderBody();
table = this._tableNode;
if (table) {
// off DOM or in an existing node attached to a different parentNode
}
} else { Y.log('Problem rendering DataTable: table not created', 'warn', 'datatable'); // On the same line to allow builder to strip the else clause
}
},
// -- Protected and private methods ---------------------------------------
_afterCaptionChange: function (e) {
this._uiUpdateCaption(e.newVal);
},
_afterColumnsChange: function (e) {
},
_afterSummaryChange: function (e) {
this._uiUpdateSummary(e.newVal);
},
_createRecordClass: function (attrs) {
var ATTRS = {},
i, len;
}
},
// name will be 'columns' or 'columns.foo'. Trim to the dot.
// TODO: support name as an index or (row,column) index pair
},
},
_initColumns: function () {
// Default column definition from the configured recordType or the
// first item in the data.
if (!columns) {
if (!attrHost) {
if (data) {
}
}
}
// TODO: merge superclass attributes up to Model?
}
}
},
_initData: function () {
// _initRecordType is run before this, so recordType will be set
// if the data array had any records. Otherwise, values is an
// empty array, so no need to call reset();
if (recordType) {
}
}
},
_initRecordType: function () {
if (!this.get('recordType')) {
columns = this._columnMap;
// Use the ModelList's specified Model class
// Or if not configured, use the construct of the first Model
// Or if the data is an array, build a class from the first item
// Or if the columns were defined, build a class from the keys
}
if (recordType) {
if (!columns) {
this._initColumns();
}
} else {
// FIXME: Edge case race condition with
// new DT().on( <any of these changes> )
// where there's not enough info to assign this.data.model
// at construction. The on/constructor subscriptions will be
// executed before this subscription.
['columnsChange', 'recordTypeChange','dataChange'],
function (e) {
// manually batch detach rather than manage separate
// subs in case the change was inadequate to populate
// recordType. But subs must be detached because the
// subscriber recurses to _initRecordType, which would
// result in duplicate subs.
// FIXME: resubscribing if there's still not enough
// info to populate recordType will place the new
// subs later in the callback queue, opening the
// race condition even more.
this._initRecordType();
// If recordType isn't set yet, _initRecordType
// will have recreated this subscription.
}
});
}
}
},
}
}
}
return map;
},
// TODO: use a _viewConfig object that can be mixed onto by class
// extensions, then pass that to either the view constructor or setAttrs
if (BodyView) {
new BodyView({
source : this,
container: this._tableNode,
cssPrefix: this._cssPrefix
}) :
}
},
if (FooterView) {
new FooterView({
source : this,
container: this._tableNode,
cssPrefix: this._cssPrefix
}) :
}
},
_renderHeader: function () {
if (HeaderView) {
new HeaderView({
source : this,
container: this._tableNode,
cssPrefix: this._cssPrefix
}) :
HeaderView; // Assume if it's not a function, it's an instance
}
// TODO: If there's no HeaderView, should I remove an existing <thead>?
},
_renderTable: function () {
if (!this._tableNode) {
}
this._uiUpdateCaption(caption);
},
if (val === null) {
val = [];
}
if (this.data) {
// FIXME: this should happen only once, but this is a side
// effect in the setter. Bad form, but I need the model set
// before calling reset()
}
// TODO: return true to decrease memory footprint?
}
// else pass through the array data, but don't assign this.data
// Let the _initData process clean up.
// TODO: return true to decrease memory footprint?
} else {
}
return val;
},
_uiUpdateCaption: function (htmlContent) {
if (htmlContent) {
if (!this._captionNode) {
}
if (caption) {
}
} else {
}
this._captionNode = caption;
} else {
if (this._captionNode) {
caption = null;
}
this._captionNode.remove(true);
delete this._captionNode;
}
if (caption) {
}
}
},
_uiUpdateSummary: function (summary) {
},
_validateRecordType: function (val) {
},
_validateView: function (val) {
}
});