1 |
efrain |
1 |
YUI.add('datatable-core', function (Y, NAME) {
|
|
|
2 |
|
|
|
3 |
/**
|
|
|
4 |
The core implementation of the `DataTable` and `DataTable.Base` Widgets.
|
|
|
5 |
|
|
|
6 |
@module datatable
|
|
|
7 |
@submodule datatable-core
|
|
|
8 |
@since 3.5.0
|
|
|
9 |
**/
|
|
|
10 |
|
|
|
11 |
var INVALID = Y.Attribute.INVALID_VALUE,
|
|
|
12 |
|
|
|
13 |
Lang = Y.Lang,
|
|
|
14 |
isFunction = Lang.isFunction,
|
|
|
15 |
isObject = Lang.isObject,
|
|
|
16 |
isArray = Lang.isArray,
|
|
|
17 |
isString = Lang.isString,
|
|
|
18 |
isNumber = Lang.isNumber,
|
|
|
19 |
|
|
|
20 |
toArray = Y.Array,
|
|
|
21 |
|
|
|
22 |
keys = Y.Object.keys,
|
|
|
23 |
|
|
|
24 |
Table;
|
|
|
25 |
|
|
|
26 |
/**
|
|
|
27 |
_API docs for this extension are included in the DataTable class._
|
|
|
28 |
|
|
|
29 |
Class extension providing the core API and structure for the DataTable Widget.
|
|
|
30 |
|
|
|
31 |
Use this class extension with Widget or another Base-based superclass to create
|
|
|
32 |
the basic DataTable model API and composing class structure.
|
|
|
33 |
|
|
|
34 |
@class DataTable.Core
|
|
|
35 |
@for DataTable
|
|
|
36 |
@since 3.5.0
|
|
|
37 |
**/
|
|
|
38 |
Table = Y.namespace('DataTable').Core = function () {};
|
|
|
39 |
|
|
|
40 |
Table.ATTRS = {
|
|
|
41 |
/**
|
|
|
42 |
Columns to include in the rendered table.
|
|
|
43 |
|
|
|
44 |
If omitted, the attributes on the configured `recordType` or the first item
|
|
|
45 |
in the `data` collection will be used as a source.
|
|
|
46 |
|
|
|
47 |
This attribute takes an array of strings or objects (mixing the two is
|
|
|
48 |
fine). Each string or object is considered a column to be rendered.
|
|
|
49 |
Strings are converted to objects, so `columns: ['first', 'last']` becomes
|
|
|
50 |
`columns: [{ key: 'first' }, { key: 'last' }]`.
|
|
|
51 |
|
|
|
52 |
DataTable.Core only concerns itself with a few properties of columns.
|
|
|
53 |
These properties are:
|
|
|
54 |
|
|
|
55 |
* `key` - Used to identify the record field/attribute containing content for
|
|
|
56 |
this column. Also used to create a default Model if no `recordType` or
|
|
|
57 |
`data` are provided during construction. If `name` is not specified, this
|
|
|
58 |
is assigned to the `_id` property (with added incrementer if the key is
|
|
|
59 |
used by multiple columns).
|
|
|
60 |
* `children` - Traversed to initialize nested column objects
|
|
|
61 |
* `name` - Used in place of, or in addition to, the `key`. Useful for
|
|
|
62 |
columns that aren't bound to a field/attribute in the record data. This
|
|
|
63 |
is assigned to the `_id` property.
|
|
|
64 |
* `id` - For backward compatibility. Implementers can specify the id of
|
|
|
65 |
the header cell. This should be avoided, if possible, to avoid the
|
|
|
66 |
potential for creating DOM elements with duplicate IDs.
|
|
|
67 |
* `field` - For backward compatibility. Implementers should use `name`.
|
|
|
68 |
* `_id` - Assigned unique-within-this-instance id for a column. By order
|
|
|
69 |
of preference, assumes the value of `name`, `key`, `id`, or `_yuid`.
|
|
|
70 |
This is used by the rendering views as well as feature module
|
|
|
71 |
as a means to identify a specific column without ambiguity (such as
|
|
|
72 |
multiple columns using the same `key`.
|
|
|
73 |
* `_yuid` - Guid stamp assigned to the column object.
|
|
|
74 |
* `_parent` - Assigned to all child columns, referencing their parent
|
|
|
75 |
column.
|
|
|
76 |
|
|
|
77 |
@attribute columns
|
|
|
78 |
@type {Object[]|String[]}
|
|
|
79 |
@default (from `recordType` ATTRS or first item in the `data`)
|
|
|
80 |
@since 3.5.0
|
|
|
81 |
**/
|
|
|
82 |
columns: {
|
|
|
83 |
// TODO: change to setter to clone input array/objects
|
|
|
84 |
validator: isArray,
|
|
|
85 |
setter: '_setColumns',
|
|
|
86 |
getter: '_getColumns'
|
|
|
87 |
},
|
|
|
88 |
|
|
|
89 |
/**
|
|
|
90 |
Model subclass to use as the `model` for the ModelList stored in the `data`
|
|
|
91 |
attribute.
|
|
|
92 |
|
|
|
93 |
If not provided, it will try really hard to figure out what to use. The
|
|
|
94 |
following attempts will be made to set a default value:
|
|
|
95 |
|
|
|
96 |
1. If the `data` attribute is set with a ModelList instance and its `model`
|
|
|
97 |
property is set, that will be used.
|
|
|
98 |
2. If the `data` attribute is set with a ModelList instance, and its
|
|
|
99 |
`model` property is unset, but it is populated, the `ATTRS` of the
|
|
|
100 |
`constructor of the first item will be used.
|
|
|
101 |
3. If the `data` attribute is set with a non-empty array, a Model subclass
|
|
|
102 |
will be generated using the keys of the first item as its `ATTRS` (see
|
|
|
103 |
the `_createRecordClass` method).
|
|
|
104 |
4. If the `columns` attribute is set, a Model subclass will be generated
|
|
|
105 |
using the columns defined with a `key`. This is least desirable because
|
|
|
106 |
columns can be duplicated or nested in a way that's not parsable.
|
|
|
107 |
5. If neither `data` nor `columns` is set or populated, a change event
|
|
|
108 |
subscriber will listen for the first to be changed and try all over
|
|
|
109 |
again.
|
|
|
110 |
|
|
|
111 |
@attribute recordType
|
|
|
112 |
@type {Function}
|
|
|
113 |
@default (see description)
|
|
|
114 |
@since 3.5.0
|
|
|
115 |
**/
|
|
|
116 |
recordType: {
|
|
|
117 |
getter: '_getRecordType',
|
|
|
118 |
setter: '_setRecordType'
|
|
|
119 |
},
|
|
|
120 |
|
|
|
121 |
/**
|
|
|
122 |
The collection of data records to display. This attribute is a pass
|
|
|
123 |
through to a `data` property, which is a ModelList instance.
|
|
|
124 |
|
|
|
125 |
If this attribute is passed a ModelList or subclass, it will be assigned to
|
|
|
126 |
the property directly. If an array of objects is passed, a new ModelList
|
|
|
127 |
will be created using the configured `recordType` as its `model` property
|
|
|
128 |
and seeded with the array.
|
|
|
129 |
|
|
|
130 |
Retrieving this attribute will return the ModelList stored in the `data`
|
|
|
131 |
property.
|
|
|
132 |
|
|
|
133 |
@attribute data
|
|
|
134 |
@type {ModelList|Object[]}
|
|
|
135 |
@default `new ModelList()`
|
|
|
136 |
@since 3.5.0
|
|
|
137 |
**/
|
|
|
138 |
data: {
|
|
|
139 |
valueFn: '_initData',
|
|
|
140 |
setter : '_setData',
|
|
|
141 |
lazyAdd: false
|
|
|
142 |
},
|
|
|
143 |
|
|
|
144 |
/**
|
|
|
145 |
Content for the `<table summary="ATTRIBUTE VALUE HERE">`. Values assigned
|
|
|
146 |
to this attribute will be HTML escaped for security.
|
|
|
147 |
|
|
|
148 |
@attribute summary
|
|
|
149 |
@type {String}
|
|
|
150 |
@default '' (empty string)
|
|
|
151 |
@since 3.5.0
|
|
|
152 |
**/
|
|
|
153 |
//summary: {},
|
|
|
154 |
|
|
|
155 |
/**
|
|
|
156 |
HTML content of an optional `<caption>` element to appear above the table.
|
|
|
157 |
Leave this config unset or set to a falsy value to remove the caption.
|
|
|
158 |
|
|
|
159 |
@attribute caption
|
|
|
160 |
@type HTML
|
|
|
161 |
@default '' (empty string)
|
|
|
162 |
@since 3.5.0
|
|
|
163 |
**/
|
|
|
164 |
//caption: {},
|
|
|
165 |
|
|
|
166 |
/**
|
|
|
167 |
Deprecated as of 3.5.0. Passes through to the `data` attribute.
|
|
|
168 |
|
|
|
169 |
WARNING: `get('recordset')` will NOT return a Recordset instance as of
|
|
|
170 |
3.5.0. This is a break in backward compatibility.
|
|
|
171 |
|
|
|
172 |
@attribute recordset
|
|
|
173 |
@type {Object[]|Recordset}
|
|
|
174 |
@deprecated Use the `data` attribute
|
|
|
175 |
@since 3.5.0
|
|
|
176 |
**/
|
|
|
177 |
recordset: {
|
|
|
178 |
setter: '_setRecordset',
|
|
|
179 |
getter: '_getRecordset',
|
|
|
180 |
lazyAdd: false
|
|
|
181 |
},
|
|
|
182 |
|
|
|
183 |
/**
|
|
|
184 |
Deprecated as of 3.5.0. Passes through to the `columns` attribute.
|
|
|
185 |
|
|
|
186 |
WARNING: `get('columnset')` will NOT return a Columnset instance as of
|
|
|
187 |
3.5.0. This is a break in backward compatibility.
|
|
|
188 |
|
|
|
189 |
@attribute columnset
|
|
|
190 |
@type {Object[]}
|
|
|
191 |
@deprecated Use the `columns` attribute
|
|
|
192 |
@since 3.5.0
|
|
|
193 |
**/
|
|
|
194 |
columnset: {
|
|
|
195 |
setter: '_setColumnset',
|
|
|
196 |
getter: '_getColumnset',
|
|
|
197 |
lazyAdd: false
|
|
|
198 |
}
|
|
|
199 |
};
|
|
|
200 |
|
|
|
201 |
Y.mix(Table.prototype, {
|
|
|
202 |
// -- Instance properties -------------------------------------------------
|
|
|
203 |
/**
|
|
|
204 |
The ModelList that manages the table's data.
|
|
|
205 |
|
|
|
206 |
@property data
|
|
|
207 |
@type {ModelList}
|
|
|
208 |
@default undefined (initially unset)
|
|
|
209 |
@since 3.5.0
|
|
|
210 |
**/
|
|
|
211 |
//data: null,
|
|
|
212 |
|
|
|
213 |
// -- Public methods ------------------------------------------------------
|
|
|
214 |
|
|
|
215 |
/**
|
|
|
216 |
Gets the column configuration object for the given key, name, or index. For
|
|
|
217 |
nested columns, `name` can be an array of indexes, each identifying the index
|
|
|
218 |
of that column in the respective parent's "children" array.
|
|
|
219 |
|
|
|
220 |
If you pass a column object, it will be returned.
|
|
|
221 |
|
|
|
222 |
For columns with keys, you can also fetch the column with
|
|
|
223 |
`instance.get('columns.foo')`.
|
|
|
224 |
|
|
|
225 |
@method getColumn
|
|
|
226 |
@param {String|Number|Number[]} name Key, "name", index, or index array to
|
|
|
227 |
identify the column
|
|
|
228 |
@return {Object} the column configuration object
|
|
|
229 |
@since 3.5.0
|
|
|
230 |
**/
|
|
|
231 |
getColumn: function (name) {
|
|
|
232 |
var col, columns, i, len, cols;
|
|
|
233 |
|
|
|
234 |
if (isObject(name) && !isArray(name)) {
|
|
|
235 |
if (name && name._node) {
|
|
|
236 |
col = this.body.getColumn(name);
|
|
|
237 |
} else {
|
|
|
238 |
col = name;
|
|
|
239 |
}
|
|
|
240 |
} else {
|
|
|
241 |
col = this.get('columns.' + name);
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
if (col) {
|
|
|
245 |
return col;
|
|
|
246 |
}
|
|
|
247 |
|
|
|
248 |
columns = this.get('columns');
|
|
|
249 |
|
|
|
250 |
if (isNumber(name) || isArray(name)) {
|
|
|
251 |
name = toArray(name);
|
|
|
252 |
cols = columns;
|
|
|
253 |
|
|
|
254 |
for (i = 0, len = name.length - 1; cols && i < len; ++i) {
|
|
|
255 |
cols = cols[name[i]] && cols[name[i]].children;
|
|
|
256 |
}
|
|
|
257 |
|
|
|
258 |
return (cols && cols[name[i]]) || null;
|
|
|
259 |
}
|
|
|
260 |
|
|
|
261 |
return null;
|
|
|
262 |
},
|
|
|
263 |
|
|
|
264 |
/**
|
|
|
265 |
Returns the Model associated to the record `id`, `clientId`, or index (not
|
|
|
266 |
row index). If none of those yield a Model from the `data` ModelList, the
|
|
|
267 |
arguments will be passed to the `view` instance's `getRecord` method
|
|
|
268 |
if it has one.
|
|
|
269 |
|
|
|
270 |
If no Model can be found, `null` is returned.
|
|
|
271 |
|
|
|
272 |
@method getRecord
|
|
|
273 |
@param {Number|String|Node} seed Record `id`, `clientId`, index, Node, or
|
|
|
274 |
identifier for a row or child element
|
|
|
275 |
@return {Model}
|
|
|
276 |
@since 3.5.0
|
|
|
277 |
**/
|
|
|
278 |
getRecord: function (seed) {
|
|
|
279 |
var record = this.data.getById(seed) || this.data.getByClientId(seed);
|
|
|
280 |
|
|
|
281 |
if (!record) {
|
|
|
282 |
if (isNumber(seed)) {
|
|
|
283 |
record = this.data.item(seed);
|
|
|
284 |
}
|
|
|
285 |
|
|
|
286 |
// TODO: this should be split out to base somehow
|
|
|
287 |
if (!record && this.view && this.view.getRecord) {
|
|
|
288 |
record = this.view.getRecord.apply(this.view, arguments);
|
|
|
289 |
}
|
|
|
290 |
}
|
|
|
291 |
|
|
|
292 |
return record || null;
|
|
|
293 |
},
|
|
|
294 |
|
|
|
295 |
// -- Protected and private properties and methods ------------------------
|
|
|
296 |
|
|
|
297 |
/**
|
|
|
298 |
This tells `Y.Base` that it should create ad-hoc attributes for config
|
|
|
299 |
properties passed to DataTable's constructor. This is useful for setting
|
|
|
300 |
configurations on the DataTable that are intended for the rendering View(s).
|
|
|
301 |
|
|
|
302 |
@property _allowAdHocAttrs
|
|
|
303 |
@type Boolean
|
|
|
304 |
@default true
|
|
|
305 |
@protected
|
|
|
306 |
@since 3.6.0
|
|
|
307 |
**/
|
|
|
308 |
_allowAdHocAttrs: true,
|
|
|
309 |
|
|
|
310 |
/**
|
|
|
311 |
A map of column key to column configuration objects parsed from the
|
|
|
312 |
`columns` attribute.
|
|
|
313 |
|
|
|
314 |
@property _columnMap
|
|
|
315 |
@type {Object}
|
|
|
316 |
@default undefined (initially unset)
|
|
|
317 |
@protected
|
|
|
318 |
@since 3.5.0
|
|
|
319 |
**/
|
|
|
320 |
//_columnMap: null,
|
|
|
321 |
|
|
|
322 |
/**
|
|
|
323 |
The Node instance of the table containing the data rows. This is set when
|
|
|
324 |
the table is rendered. It may also be set by progressive enhancement,
|
|
|
325 |
though this extension does not provide the logic to parse from source.
|
|
|
326 |
|
|
|
327 |
@property _tableNode
|
|
|
328 |
@type {Node}
|
|
|
329 |
@default undefined (initially unset)
|
|
|
330 |
@protected
|
|
|
331 |
@since 3.5.0
|
|
|
332 |
**/
|
|
|
333 |
//_tableNode: null,
|
|
|
334 |
|
|
|
335 |
/**
|
|
|
336 |
Updates the `_columnMap` property in response to changes in the `columns`
|
|
|
337 |
attribute.
|
|
|
338 |
|
|
|
339 |
@method _afterColumnsChange
|
|
|
340 |
@param {EventFacade} e The `columnsChange` event object
|
|
|
341 |
@protected
|
|
|
342 |
@since 3.5.0
|
|
|
343 |
**/
|
|
|
344 |
_afterColumnsChange: function (e) {
|
|
|
345 |
this._setColumnMap(e.newVal);
|
|
|
346 |
},
|
|
|
347 |
|
|
|
348 |
/**
|
|
|
349 |
Updates the `modelList` attributes of the rendered views in response to the
|
|
|
350 |
`data` attribute being assigned a new ModelList.
|
|
|
351 |
|
|
|
352 |
@method _afterDataChange
|
|
|
353 |
@param {EventFacade} e the `dataChange` event
|
|
|
354 |
@protected
|
|
|
355 |
@since 3.5.0
|
|
|
356 |
**/
|
|
|
357 |
_afterDataChange: function (e) {
|
|
|
358 |
var modelList = e.newVal;
|
|
|
359 |
|
|
|
360 |
this.data = e.newVal;
|
|
|
361 |
|
|
|
362 |
if (!this.get('columns') && modelList.size()) {
|
|
|
363 |
// TODO: this will cause a re-render twice because the Views are
|
|
|
364 |
// subscribed to columnsChange
|
|
|
365 |
this._initColumns();
|
|
|
366 |
}
|
|
|
367 |
},
|
|
|
368 |
|
|
|
369 |
/**
|
|
|
370 |
Assigns to the new recordType as the model for the data ModelList
|
|
|
371 |
|
|
|
372 |
@method _afterRecordTypeChange
|
|
|
373 |
@param {EventFacade} e recordTypeChange event
|
|
|
374 |
@protected
|
|
|
375 |
@since 3.6.0
|
|
|
376 |
**/
|
|
|
377 |
_afterRecordTypeChange: function (e) {
|
|
|
378 |
var data = this.data.toJSON();
|
|
|
379 |
|
|
|
380 |
this.data.model = e.newVal;
|
|
|
381 |
|
|
|
382 |
this.data.reset(data);
|
|
|
383 |
|
|
|
384 |
if (!this.get('columns') && data) {
|
|
|
385 |
if (data.length) {
|
|
|
386 |
this._initColumns();
|
|
|
387 |
} else {
|
|
|
388 |
this.set('columns', keys(e.newVal.ATTRS));
|
|
|
389 |
}
|
|
|
390 |
}
|
|
|
391 |
},
|
|
|
392 |
|
|
|
393 |
/**
|
|
|
394 |
Creates a Model subclass from an array of attribute names or an object of
|
|
|
395 |
attribute definitions. This is used to generate a class suitable to
|
|
|
396 |
represent the data passed to the `data` attribute if no `recordType` is
|
|
|
397 |
set.
|
|
|
398 |
|
|
|
399 |
@method _createRecordClass
|
|
|
400 |
@param {String[]|Object} attrs Names assigned to the Model subclass's
|
|
|
401 |
`ATTRS` or its entire `ATTRS` definition object
|
|
|
402 |
@return {Model}
|
|
|
403 |
@protected
|
|
|
404 |
@since 3.5.0
|
|
|
405 |
**/
|
|
|
406 |
_createRecordClass: function (attrs) {
|
|
|
407 |
var ATTRS, i, len;
|
|
|
408 |
|
|
|
409 |
if (isArray(attrs)) {
|
|
|
410 |
ATTRS = {};
|
|
|
411 |
|
|
|
412 |
for (i = 0, len = attrs.length; i < len; ++i) {
|
|
|
413 |
ATTRS[attrs[i]] = {};
|
|
|
414 |
}
|
|
|
415 |
} else if (isObject(attrs)) {
|
|
|
416 |
ATTRS = attrs;
|
|
|
417 |
}
|
|
|
418 |
|
|
|
419 |
return Y.Base.create('record', Y.Model, [], null, { ATTRS: ATTRS });
|
|
|
420 |
},
|
|
|
421 |
|
|
|
422 |
/**
|
|
|
423 |
Tears down the instance.
|
|
|
424 |
|
|
|
425 |
@method destructor
|
|
|
426 |
@protected
|
|
|
427 |
@since 3.6.0
|
|
|
428 |
**/
|
|
|
429 |
destructor: function () {
|
|
|
430 |
new Y.EventHandle(Y.Object.values(this._eventHandles)).detach();
|
|
|
431 |
},
|
|
|
432 |
|
|
|
433 |
/**
|
|
|
434 |
The getter for the `columns` attribute. Returns the array of column
|
|
|
435 |
configuration objects if `instance.get('columns')` is called, or the
|
|
|
436 |
specific column object if `instance.get('columns.columnKey')` is called.
|
|
|
437 |
|
|
|
438 |
@method _getColumns
|
|
|
439 |
@param {Object[]} columns The full array of column objects
|
|
|
440 |
@param {String} name The attribute name requested
|
|
|
441 |
(e.g. 'columns' or 'columns.foo');
|
|
|
442 |
@protected
|
|
|
443 |
@since 3.5.0
|
|
|
444 |
**/
|
|
|
445 |
_getColumns: function (columns, name) {
|
|
|
446 |
// Workaround for an attribute oddity (ticket #2529254)
|
|
|
447 |
// getter is expected to return an object if get('columns.foo') is called.
|
|
|
448 |
// Note 'columns.' is 8 characters
|
|
|
449 |
return name.length > 8 ? this._columnMap : columns;
|
|
|
450 |
},
|
|
|
451 |
|
|
|
452 |
/**
|
|
|
453 |
Relays the `get()` request for the deprecated `columnset` attribute to the
|
|
|
454 |
`columns` attribute.
|
|
|
455 |
|
|
|
456 |
THIS BREAKS BACKWARD COMPATIBILITY. 3.4.1 and prior implementations will
|
|
|
457 |
expect a Columnset instance returned from `get('columnset')`.
|
|
|
458 |
|
|
|
459 |
@method _getColumnset
|
|
|
460 |
@param {Object} ignored The current value stored in the `columnset` state
|
|
|
461 |
@param {String} name The attribute name requested
|
|
|
462 |
(e.g. 'columnset' or 'columnset.foo');
|
|
|
463 |
@deprecated This will be removed with the `columnset` attribute in a future
|
|
|
464 |
version.
|
|
|
465 |
@protected
|
|
|
466 |
@since 3.5.0
|
|
|
467 |
**/
|
|
|
468 |
_getColumnset: function (_, name) {
|
|
|
469 |
return this.get(name.replace(/^columnset/, 'columns'));
|
|
|
470 |
},
|
|
|
471 |
|
|
|
472 |
/**
|
|
|
473 |
Returns the Model class of the instance's `data` attribute ModelList. If
|
|
|
474 |
not set, returns the explicitly configured value.
|
|
|
475 |
|
|
|
476 |
@method _getRecordType
|
|
|
477 |
@param {Model} val The currently configured value
|
|
|
478 |
@return {Model}
|
|
|
479 |
**/
|
|
|
480 |
_getRecordType: function (val) {
|
|
|
481 |
// Prefer the value stored in the attribute because the attribute
|
|
|
482 |
// change event defaultFn sets e.newVal = this.get('recordType')
|
|
|
483 |
// before notifying the after() subs. But if this getter returns
|
|
|
484 |
// this.data.model, then after() subs would get e.newVal === previous
|
|
|
485 |
// model before _afterRecordTypeChange can set
|
|
|
486 |
// this.data.model = e.newVal
|
|
|
487 |
return val || (this.data && this.data.model);
|
|
|
488 |
},
|
|
|
489 |
|
|
|
490 |
/**
|
|
|
491 |
Initializes the `_columnMap` property from the configured `columns`
|
|
|
492 |
attribute. If `columns` is not set, but there are records in the `data`
|
|
|
493 |
ModelList, use
|
|
|
494 |
`ATTRS` of that class.
|
|
|
495 |
|
|
|
496 |
@method _initColumns
|
|
|
497 |
@protected
|
|
|
498 |
@since 3.5.0
|
|
|
499 |
**/
|
|
|
500 |
_initColumns: function () {
|
|
|
501 |
var columns = this.get('columns') || [],
|
|
|
502 |
item;
|
|
|
503 |
|
|
|
504 |
// Default column definition from the configured recordType
|
|
|
505 |
if (!columns.length && this.data.size()) {
|
|
|
506 |
// TODO: merge superclass attributes up to Model?
|
|
|
507 |
item = this.data.item(0);
|
|
|
508 |
|
|
|
509 |
if (item.toJSON) {
|
|
|
510 |
item = item.toJSON();
|
|
|
511 |
}
|
|
|
512 |
|
|
|
513 |
this.set('columns', keys(item));
|
|
|
514 |
}
|
|
|
515 |
|
|
|
516 |
this._setColumnMap(columns);
|
|
|
517 |
},
|
|
|
518 |
|
|
|
519 |
/**
|
|
|
520 |
Sets up the change event subscriptions to maintain internal state.
|
|
|
521 |
|
|
|
522 |
@method _initCoreEvents
|
|
|
523 |
@protected
|
|
|
524 |
@since 3.6.0
|
|
|
525 |
**/
|
|
|
526 |
_initCoreEvents: function () {
|
|
|
527 |
this._eventHandles.coreAttrChanges = this.after({
|
|
|
528 |
columnsChange : Y.bind('_afterColumnsChange', this),
|
|
|
529 |
recordTypeChange: Y.bind('_afterRecordTypeChange', this),
|
|
|
530 |
dataChange : Y.bind('_afterDataChange', this)
|
|
|
531 |
});
|
|
|
532 |
},
|
|
|
533 |
|
|
|
534 |
/**
|
|
|
535 |
Defaults the `data` attribute to an empty ModelList if not set during
|
|
|
536 |
construction. Uses the configured `recordType` for the ModelList's `model`
|
|
|
537 |
proeprty if set.
|
|
|
538 |
|
|
|
539 |
@method _initData
|
|
|
540 |
@protected
|
|
|
541 |
@return {ModelList}
|
|
|
542 |
@since 3.6.0
|
|
|
543 |
**/
|
|
|
544 |
_initData: function () {
|
|
|
545 |
var recordType = this.get('recordType'),
|
|
|
546 |
// TODO: LazyModelList if recordType doesn't have complex ATTRS
|
|
|
547 |
modelList = new Y.ModelList();
|
|
|
548 |
|
|
|
549 |
if (recordType) {
|
|
|
550 |
modelList.model = recordType;
|
|
|
551 |
}
|
|
|
552 |
|
|
|
553 |
return modelList;
|
|
|
554 |
},
|
|
|
555 |
|
|
|
556 |
/**
|
|
|
557 |
Initializes the instance's `data` property from the value of the `data`
|
|
|
558 |
attribute. If the attribute value is a ModelList, it is assigned directly
|
|
|
559 |
to `this.data`. If it is an array, a ModelList is created, its `model`
|
|
|
560 |
property is set to the configured `recordType` class, and it is seeded with
|
|
|
561 |
the array data. This ModelList is then assigned to `this.data`.
|
|
|
562 |
|
|
|
563 |
@method _initDataProperty
|
|
|
564 |
@param {Array|ModelList|ArrayList} data Collection of data to populate the
|
|
|
565 |
DataTable
|
|
|
566 |
@protected
|
|
|
567 |
@since 3.6.0
|
|
|
568 |
**/
|
|
|
569 |
_initDataProperty: function (data) {
|
|
|
570 |
var recordType;
|
|
|
571 |
|
|
|
572 |
if (!this.data) {
|
|
|
573 |
recordType = this.get('recordType');
|
|
|
574 |
|
|
|
575 |
if (data && data.each && data.toJSON) {
|
|
|
576 |
this.data = data;
|
|
|
577 |
|
|
|
578 |
if (recordType) {
|
|
|
579 |
this.data.model = recordType;
|
|
|
580 |
}
|
|
|
581 |
} else {
|
|
|
582 |
// TODO: customize the ModelList or read the ModelList class
|
|
|
583 |
// from a configuration option?
|
|
|
584 |
this.data = new Y.ModelList();
|
|
|
585 |
|
|
|
586 |
if (recordType) {
|
|
|
587 |
this.data.model = recordType;
|
|
|
588 |
}
|
|
|
589 |
}
|
|
|
590 |
|
|
|
591 |
// TODO: Replace this with an event relay for specific events.
|
|
|
592 |
// Using bubbling causes subscription conflicts with the models'
|
|
|
593 |
// aggregated change event and 'change' events from DOM elements
|
|
|
594 |
// inside the table (via Widget UI event).
|
|
|
595 |
this.data.addTarget(this);
|
|
|
596 |
}
|
|
|
597 |
},
|
|
|
598 |
|
|
|
599 |
/**
|
|
|
600 |
Initializes the columns, `recordType` and data ModelList.
|
|
|
601 |
|
|
|
602 |
@method initializer
|
|
|
603 |
@param {Object} config Configuration object passed to constructor
|
|
|
604 |
@protected
|
|
|
605 |
@since 3.5.0
|
|
|
606 |
**/
|
|
|
607 |
initializer: function (config) {
|
|
|
608 |
var data = config.data,
|
|
|
609 |
columns = config.columns,
|
|
|
610 |
recordType;
|
|
|
611 |
|
|
|
612 |
// Referencing config.data to allow _setData to be more stringent
|
|
|
613 |
// about its behavior
|
|
|
614 |
this._initDataProperty(data);
|
|
|
615 |
|
|
|
616 |
// Default columns from recordType ATTRS if recordType is supplied at
|
|
|
617 |
// construction. If no recordType is supplied, but the data is
|
|
|
618 |
// supplied as a non-empty array, use the keys of the first item
|
|
|
619 |
// as the columns.
|
|
|
620 |
if (!columns) {
|
|
|
621 |
recordType = (config.recordType || config.data === this.data) &&
|
|
|
622 |
this.get('recordType');
|
|
|
623 |
|
|
|
624 |
if (recordType) {
|
|
|
625 |
columns = keys(recordType.ATTRS);
|
|
|
626 |
} else if (isArray(data) && data.length) {
|
|
|
627 |
columns = keys(data[0]);
|
|
|
628 |
}
|
|
|
629 |
|
|
|
630 |
if (columns) {
|
|
|
631 |
this.set('columns', columns);
|
|
|
632 |
}
|
|
|
633 |
}
|
|
|
634 |
|
|
|
635 |
this._initColumns();
|
|
|
636 |
|
|
|
637 |
this._eventHandles = {};
|
|
|
638 |
|
|
|
639 |
this._initCoreEvents();
|
|
|
640 |
},
|
|
|
641 |
|
|
|
642 |
/**
|
|
|
643 |
Iterates the array of column configurations to capture all columns with a
|
|
|
644 |
`key` property. An map is built with column keys as the property name and
|
|
|
645 |
the corresponding column object as the associated value. This map is then
|
|
|
646 |
assigned to the instance's `_columnMap` property.
|
|
|
647 |
|
|
|
648 |
@method _setColumnMap
|
|
|
649 |
@param {Object[]|String[]} columns The array of column config objects
|
|
|
650 |
@protected
|
|
|
651 |
@since 3.6.0
|
|
|
652 |
**/
|
|
|
653 |
_setColumnMap: function (columns) {
|
|
|
654 |
var map = {};
|
|
|
655 |
|
|
|
656 |
function process(cols) {
|
|
|
657 |
var i, len, col, key;
|
|
|
658 |
|
|
|
659 |
for (i = 0, len = cols.length; i < len; ++i) {
|
|
|
660 |
col = cols[i];
|
|
|
661 |
key = col.key;
|
|
|
662 |
|
|
|
663 |
// First in wins for multiple columns with the same key
|
|
|
664 |
// because the first call to genId (in _setColumns) will
|
|
|
665 |
// return the same key, which will then be overwritten by the
|
|
|
666 |
// subsequent same-keyed column. So table.getColumn(key) would
|
|
|
667 |
// return the last same-keyed column.
|
|
|
668 |
if (key && !map[key]) {
|
|
|
669 |
map[key] = col;
|
|
|
670 |
}
|
|
|
671 |
//TODO: named columns can conflict with keyed columns
|
|
|
672 |
map[col._id] = col;
|
|
|
673 |
|
|
|
674 |
if (col.children) {
|
|
|
675 |
process(col.children);
|
|
|
676 |
}
|
|
|
677 |
}
|
|
|
678 |
}
|
|
|
679 |
|
|
|
680 |
process(columns);
|
|
|
681 |
|
|
|
682 |
this._columnMap = map;
|
|
|
683 |
},
|
|
|
684 |
|
|
|
685 |
/**
|
|
|
686 |
Translates string columns into objects with that string as the value of its
|
|
|
687 |
`key` property.
|
|
|
688 |
|
|
|
689 |
All columns are assigned a `_yuid` stamp and `_id` property corresponding
|
|
|
690 |
to the column's configured `name` or `key` property with any spaces
|
|
|
691 |
replaced with dashes. If the same `name` or `key` appears in multiple
|
|
|
692 |
columns, subsequent appearances will have their `_id` appended with an
|
|
|
693 |
incrementing number (e.g. if column "foo" is included in the `columns`
|
|
|
694 |
attribute twice, the first will get `_id` of "foo", and the second an `_id`
|
|
|
695 |
of "foo1"). Columns that are children of other columns will have the
|
|
|
696 |
`_parent` property added, assigned the column object to which they belong.
|
|
|
697 |
|
|
|
698 |
@method _setColumns
|
|
|
699 |
@param {null|Object[]|String[]} val Array of config objects or strings
|
|
|
700 |
@return {null|Object[]}
|
|
|
701 |
@protected
|
|
|
702 |
**/
|
|
|
703 |
_setColumns: function (val) {
|
|
|
704 |
var keys = {},
|
|
|
705 |
known = [],
|
|
|
706 |
knownCopies = [],
|
|
|
707 |
arrayIndex = Y.Array.indexOf;
|
|
|
708 |
|
|
|
709 |
function copyObj(o) {
|
|
|
710 |
var copy = {},
|
|
|
711 |
key, val, i;
|
|
|
712 |
|
|
|
713 |
known.push(o);
|
|
|
714 |
knownCopies.push(copy);
|
|
|
715 |
|
|
|
716 |
for (key in o) {
|
|
|
717 |
if (o.hasOwnProperty(key)) {
|
|
|
718 |
val = o[key];
|
|
|
719 |
|
|
|
720 |
if (isArray(val)) {
|
|
|
721 |
copy[key] = val.slice();
|
|
|
722 |
} else if (isObject(val, true)) {
|
|
|
723 |
i = arrayIndex(known, val);
|
|
|
724 |
|
|
|
725 |
copy[key] = i === -1 ? copyObj(val) : knownCopies[i];
|
|
|
726 |
} else {
|
|
|
727 |
copy[key] = o[key];
|
|
|
728 |
}
|
|
|
729 |
}
|
|
|
730 |
}
|
|
|
731 |
|
|
|
732 |
return copy;
|
|
|
733 |
}
|
|
|
734 |
|
|
|
735 |
function genId(name) {
|
|
|
736 |
// Sanitize the name for use in generated CSS classes.
|
|
|
737 |
// TODO: is there more to do for other uses of _id?
|
|
|
738 |
name = name.replace(/\s+/, '-');
|
|
|
739 |
|
|
|
740 |
if (keys[name]) {
|
|
|
741 |
name += (keys[name]++);
|
|
|
742 |
} else {
|
|
|
743 |
keys[name] = 1;
|
|
|
744 |
}
|
|
|
745 |
|
|
|
746 |
return name;
|
|
|
747 |
}
|
|
|
748 |
|
|
|
749 |
function process(cols, parent) {
|
|
|
750 |
var columns = [],
|
|
|
751 |
i, len, col, yuid;
|
|
|
752 |
|
|
|
753 |
for (i = 0, len = cols.length; i < len; ++i) {
|
|
|
754 |
columns[i] = // chained assignment
|
|
|
755 |
col = isString(cols[i]) ? { key: cols[i] } : copyObj(cols[i]);
|
|
|
756 |
|
|
|
757 |
yuid = Y.stamp(col);
|
|
|
758 |
|
|
|
759 |
// For backward compatibility
|
|
|
760 |
if (!col.id) {
|
|
|
761 |
// Implementers can shoot themselves in the foot by setting
|
|
|
762 |
// this config property to a non-unique value
|
|
|
763 |
col.id = yuid;
|
|
|
764 |
}
|
|
|
765 |
if (col.field) {
|
|
|
766 |
// Field is now known as "name" to avoid confusion with data
|
|
|
767 |
// fields or schema.resultFields
|
|
|
768 |
col.name = col.field;
|
|
|
769 |
}
|
|
|
770 |
|
|
|
771 |
if (parent) {
|
|
|
772 |
col._parent = parent;
|
|
|
773 |
} else {
|
|
|
774 |
delete col._parent;
|
|
|
775 |
}
|
|
|
776 |
|
|
|
777 |
// Unique id based on the column's configured name or key,
|
|
|
778 |
// falling back to the yuid. Duplicates will have a counter
|
|
|
779 |
// added to the end.
|
|
|
780 |
col._id = genId(col.name || col.key || col.id);
|
|
|
781 |
|
|
|
782 |
if (isArray(col.children)) {
|
|
|
783 |
col.children = process(col.children, col);
|
|
|
784 |
}
|
|
|
785 |
}
|
|
|
786 |
|
|
|
787 |
return columns;
|
|
|
788 |
}
|
|
|
789 |
|
|
|
790 |
return val && process(val);
|
|
|
791 |
},
|
|
|
792 |
|
|
|
793 |
/**
|
|
|
794 |
Relays attribute assignments of the deprecated `columnset` attribute to the
|
|
|
795 |
`columns` attribute. If a Columnset is object is passed, its basic object
|
|
|
796 |
structure is mined.
|
|
|
797 |
|
|
|
798 |
@method _setColumnset
|
|
|
799 |
@param {Array|Columnset} val The columnset value to relay
|
|
|
800 |
@deprecated This will be removed with the deprecated `columnset` attribute
|
|
|
801 |
in a later version.
|
|
|
802 |
@protected
|
|
|
803 |
@since 3.5.0
|
|
|
804 |
**/
|
|
|
805 |
_setColumnset: function (val) {
|
|
|
806 |
this.set('columns', val);
|
|
|
807 |
|
|
|
808 |
return isArray(val) ? val : INVALID;
|
|
|
809 |
},
|
|
|
810 |
|
|
|
811 |
/**
|
|
|
812 |
Accepts an object with `each` and `getAttrs` (preferably a ModelList or
|
|
|
813 |
subclass) or an array of data objects. If an array is passes, it will
|
|
|
814 |
create a ModelList to wrap the data. In doing so, it will set the created
|
|
|
815 |
ModelList's `model` property to the class in the `recordType` attribute,
|
|
|
816 |
which will be defaulted if not yet set.
|
|
|
817 |
|
|
|
818 |
If the `data` property is already set with a ModelList, passing an array as
|
|
|
819 |
the value will call the ModelList's `reset()` method with that array rather
|
|
|
820 |
than replacing the stored ModelList wholesale.
|
|
|
821 |
|
|
|
822 |
Any non-ModelList-ish and non-array value is invalid.
|
|
|
823 |
|
|
|
824 |
@method _setData
|
|
|
825 |
@protected
|
|
|
826 |
@since 3.5.0
|
|
|
827 |
**/
|
|
|
828 |
_setData: function (val) {
|
|
|
829 |
if (val === null) {
|
|
|
830 |
val = [];
|
|
|
831 |
}
|
|
|
832 |
|
|
|
833 |
if (isArray(val)) {
|
|
|
834 |
this._initDataProperty();
|
|
|
835 |
|
|
|
836 |
// silent to prevent subscribers to both reset and dataChange
|
|
|
837 |
// from reacting to the change twice.
|
|
|
838 |
// TODO: would it be better to return INVALID to silence the
|
|
|
839 |
// dataChange event, or even allow both events?
|
|
|
840 |
this.data.reset(val, { silent: true });
|
|
|
841 |
|
|
|
842 |
// Return the instance ModelList to avoid storing unprocessed
|
|
|
843 |
// data in the state and their vivified Model representations in
|
|
|
844 |
// the instance's data property. Decreases memory consumption.
|
|
|
845 |
val = this.data;
|
|
|
846 |
} else if (!val || !val.each || !val.toJSON) {
|
|
|
847 |
// ModelList/ArrayList duck typing
|
|
|
848 |
val = INVALID;
|
|
|
849 |
}
|
|
|
850 |
|
|
|
851 |
return val;
|
|
|
852 |
},
|
|
|
853 |
|
|
|
854 |
/**
|
|
|
855 |
Relays the value assigned to the deprecated `recordset` attribute to the
|
|
|
856 |
`data` attribute. If a Recordset instance is passed, the raw object data
|
|
|
857 |
will be culled from it.
|
|
|
858 |
|
|
|
859 |
@method _setRecordset
|
|
|
860 |
@param {Object[]|Recordset} val The recordset value to relay
|
|
|
861 |
@deprecated This will be removed with the deprecated `recordset` attribute
|
|
|
862 |
in a later version.
|
|
|
863 |
@protected
|
|
|
864 |
@since 3.5.0
|
|
|
865 |
**/
|
|
|
866 |
_setRecordset: function (val) {
|
|
|
867 |
var data;
|
|
|
868 |
|
|
|
869 |
if (val && Y.Recordset && val instanceof Y.Recordset) {
|
|
|
870 |
data = [];
|
|
|
871 |
val.each(function (record) {
|
|
|
872 |
data.push(record.get('data'));
|
|
|
873 |
});
|
|
|
874 |
val = data;
|
|
|
875 |
}
|
|
|
876 |
|
|
|
877 |
this.set('data', val);
|
|
|
878 |
|
|
|
879 |
return val;
|
|
|
880 |
},
|
|
|
881 |
|
|
|
882 |
/**
|
|
|
883 |
Accepts a Base subclass (preferably a Model subclass). Alternately, it will
|
|
|
884 |
generate a custom Model subclass from an array of attribute names or an
|
|
|
885 |
object defining attributes and their respective configurations (it is
|
|
|
886 |
assigned as the `ATTRS` of the new class).
|
|
|
887 |
|
|
|
888 |
Any other value is invalid.
|
|
|
889 |
|
|
|
890 |
@method _setRecordType
|
|
|
891 |
@param {Function|String[]|Object} val The Model subclass, array of
|
|
|
892 |
attribute names, or the `ATTRS` definition for a custom model
|
|
|
893 |
subclass
|
|
|
894 |
@return {Function} A Base/Model subclass
|
|
|
895 |
@protected
|
|
|
896 |
@since 3.5.0
|
|
|
897 |
**/
|
|
|
898 |
_setRecordType: function (val) {
|
|
|
899 |
var modelClass;
|
|
|
900 |
|
|
|
901 |
// Duck type based on known/likely consumed APIs
|
|
|
902 |
if (isFunction(val) && val.prototype.toJSON && val.prototype.setAttrs) {
|
|
|
903 |
modelClass = val;
|
|
|
904 |
} else if (isObject(val)) {
|
|
|
905 |
modelClass = this._createRecordClass(val);
|
|
|
906 |
}
|
|
|
907 |
|
|
|
908 |
return modelClass || INVALID;
|
|
|
909 |
}
|
|
|
910 |
|
|
|
911 |
});
|
|
|
912 |
|
|
|
913 |
|
|
|
914 |
|
|
|
915 |
/**
|
|
|
916 |
_This is a documentation entry only_
|
|
|
917 |
|
|
|
918 |
Columns are described by object literals with a set of properties.
|
|
|
919 |
There is not an actual `DataTable.Column` class.
|
|
|
920 |
However, for the purpose of documenting it, this pseudo-class is declared here.
|
|
|
921 |
|
|
|
922 |
DataTables accept an array of column definitions in their [columns](DataTable.html#attr_columns)
|
|
|
923 |
attribute. Each entry in this array is a column definition which may contain
|
|
|
924 |
any combination of the properties listed below.
|
|
|
925 |
|
|
|
926 |
There are no mandatory properties though a column will usually have a
|
|
|
927 |
[key](#property_key) property to reference the data it is supposed to show.
|
|
|
928 |
The [columns](DataTable.html#attr_columns) attribute can accept a plain string
|
|
|
929 |
in lieu of an object literal, which is the equivalent of an object with the
|
|
|
930 |
[key](#property_key) property set to that string.
|
|
|
931 |
|
|
|
932 |
@class DataTable.Column
|
|
|
933 |
*/
|
|
|
934 |
|
|
|
935 |
/**
|
|
|
936 |
Binds the column values to the named property in the [data](DataTable.html#attr_data).
|
|
|
937 |
|
|
|
938 |
Optional if [formatter](#property_formatter), [nodeFormatter](#property_nodeFormatter),
|
|
|
939 |
or [cellTemplate](#property_cellTemplate) is used to populate the content.
|
|
|
940 |
|
|
|
941 |
It should not be set if [children](#property_children) is set.
|
|
|
942 |
|
|
|
943 |
The value is used for the [\_id](#property__id) property unless the [name](#property_name)
|
|
|
944 |
property is also set.
|
|
|
945 |
|
|
|
946 |
{ key: 'username' }
|
|
|
947 |
|
|
|
948 |
The above column definition can be reduced to this:
|
|
|
949 |
|
|
|
950 |
'username'
|
|
|
951 |
|
|
|
952 |
@property key
|
|
|
953 |
@type String
|
|
|
954 |
*/
|
|
|
955 |
/**
|
|
|
956 |
An identifier that can be used to locate a column via
|
|
|
957 |
[getColumn](DataTable.html#method_getColumn)
|
|
|
958 |
or style columns with class `yui3-datatable-col-NAME` after dropping characters
|
|
|
959 |
that are not valid for CSS class names.
|
|
|
960 |
|
|
|
961 |
It defaults to the [key](#property_key).
|
|
|
962 |
|
|
|
963 |
The value is used for the [\_id](#property__id) property.
|
|
|
964 |
|
|
|
965 |
{ name: 'fullname', formatter: ... }
|
|
|
966 |
|
|
|
967 |
@property name
|
|
|
968 |
@type String
|
|
|
969 |
*/
|
|
|
970 |
/**
|
|
|
971 |
An alias for [name](#property_name) for backward compatibility.
|
|
|
972 |
|
|
|
973 |
{ field: 'fullname', formatter: ... }
|
|
|
974 |
|
|
|
975 |
@property field
|
|
|
976 |
@type String
|
|
|
977 |
*/
|
|
|
978 |
/**
|
|
|
979 |
Overrides the default unique id assigned `<th id="HERE">`.
|
|
|
980 |
|
|
|
981 |
__Use this with caution__, since it can result in
|
|
|
982 |
duplicate ids in the DOM.
|
|
|
983 |
|
|
|
984 |
{
|
|
|
985 |
name: 'checkAll',
|
|
|
986 |
id: 'check-all',
|
|
|
987 |
label: ...
|
|
|
988 |
formatter: ...
|
|
|
989 |
}
|
|
|
990 |
|
|
|
991 |
@property id
|
|
|
992 |
@type String
|
|
|
993 |
*/
|
|
|
994 |
/**
|
|
|
995 |
HTML to populate the header `<th>` for the column.
|
|
|
996 |
It defaults to the value of the [key](#property_key) property or the text
|
|
|
997 |
`Column n` where _n_ is an ordinal number.
|
|
|
998 |
|
|
|
999 |
{ key: 'MfgvaPrtNum', label: 'Part Number' }
|
|
|
1000 |
|
|
|
1001 |
@property label
|
|
|
1002 |
@type {String}
|
|
|
1003 |
*/
|
|
|
1004 |
/**
|
|
|
1005 |
Used to create stacked headers.
|
|
|
1006 |
|
|
|
1007 |
Child columns may also contain `children`. There is no limit
|
|
|
1008 |
to the depth of nesting.
|
|
|
1009 |
|
|
|
1010 |
Columns configured with `children` are for display only and
|
|
|
1011 |
<strong>should not</strong> be configured with a [key](#property_key).
|
|
|
1012 |
Configurations relating to the display of data, such as
|
|
|
1013 |
[formatter](#property_formatter), [nodeFormatter](#property_nodeFormatter),
|
|
|
1014 |
[emptyCellValue](#property_emptyCellValue), etc. are ignored.
|
|
|
1015 |
|
|
|
1016 |
{ label: 'Name', children: [
|
|
|
1017 |
{ key: 'firstName', label: 'First`},
|
|
|
1018 |
{ key: 'lastName', label: 'Last`}
|
|
|
1019 |
]}
|
|
|
1020 |
|
|
|
1021 |
@property children
|
|
|
1022 |
@type Array
|
|
|
1023 |
*/
|
|
|
1024 |
/**
|
|
|
1025 |
Assigns the value `<th abbr="HERE">`.
|
|
|
1026 |
|
|
|
1027 |
{
|
|
|
1028 |
key : 'forecast',
|
|
|
1029 |
label: '1yr Target Forecast',
|
|
|
1030 |
abbr : 'Forecast'
|
|
|
1031 |
}
|
|
|
1032 |
|
|
|
1033 |
@property abbr
|
|
|
1034 |
@type String
|
|
|
1035 |
*/
|
|
|
1036 |
/**
|
|
|
1037 |
Assigns the value `<th title="HERE">`.
|
|
|
1038 |
|
|
|
1039 |
{
|
|
|
1040 |
key : 'forecast',
|
|
|
1041 |
label: '1yr Target Forecast',
|
|
|
1042 |
title: 'Target Forecast for the Next 12 Months'
|
|
|
1043 |
}
|
|
|
1044 |
|
|
|
1045 |
@property title
|
|
|
1046 |
@type String
|
|
|
1047 |
*/
|
|
|
1048 |
/**
|
|
|
1049 |
Overrides the default [CELL_TEMPLATE](DataTable.HeaderView.html#property_CELL_TEMPLATE)
|
|
|
1050 |
used by `Y.DataTable.HeaderView` to render the header cell
|
|
|
1051 |
for this column. This is necessary when more control is
|
|
|
1052 |
needed over the markup for the header itself, rather than
|
|
|
1053 |
its content.
|
|
|
1054 |
|
|
|
1055 |
Use the [label](#property_label) configuration if you don't need to
|
|
|
1056 |
customize the `<th>` iteself.
|
|
|
1057 |
|
|
|
1058 |
Implementers are strongly encouraged to preserve at least
|
|
|
1059 |
the `{id}` and `{_id}` placeholders in the custom value.
|
|
|
1060 |
|
|
|
1061 |
{
|
|
|
1062 |
headerTemplate:
|
|
|
1063 |
'<th id="{id}" ' +
|
|
|
1064 |
'title="Unread" ' +
|
|
|
1065 |
'class="{className}" ' +
|
|
|
1066 |
'{_id}>●</th>'
|
|
|
1067 |
}
|
|
|
1068 |
|
|
|
1069 |
@property headerTemplate
|
|
|
1070 |
@type HTML
|
|
|
1071 |
*/
|
|
|
1072 |
/**
|
|
|
1073 |
Overrides the default [CELL_TEMPLATE](DataTable.BodyView.html#property_CELL_TEMPLATE)
|
|
|
1074 |
used by `Y.DataTable.BodyView` to render the data cells
|
|
|
1075 |
for this column. This is necessary when more control is
|
|
|
1076 |
needed over the markup for the `<td>` itself, rather than
|
|
|
1077 |
its content.
|
|
|
1078 |
|
|
|
1079 |
{
|
|
|
1080 |
key: 'id',
|
|
|
1081 |
cellTemplate:
|
|
|
1082 |
'<td class="{className}">' +
|
|
|
1083 |
'<input type="checkbox" ' +
|
|
|
1084 |
'id="{content}">' +
|
|
|
1085 |
'</td>'
|
|
|
1086 |
}
|
|
|
1087 |
|
|
|
1088 |
|
|
|
1089 |
@property cellTemplate
|
|
|
1090 |
@type String
|
|
|
1091 |
*/
|
|
|
1092 |
/**
|
|
|
1093 |
String or function used to translate the raw record data for each cell in a
|
|
|
1094 |
given column into a format better suited to display.
|
|
|
1095 |
|
|
|
1096 |
If it is a string, it will initially be assumed to be the name of one of the
|
|
|
1097 |
formatting functions in
|
|
|
1098 |
[Y.DataTable.BodyView.Formatters](DataTable.BodyView.Formatters.html).
|
|
|
1099 |
If one such formatting function exists, it will be used.
|
|
|
1100 |
|
|
|
1101 |
If no such named formatter is found, it will be assumed to be a template
|
|
|
1102 |
string and will be expanded. The placeholders can contain the key to any
|
|
|
1103 |
field in the record or the placeholder `{value}` which represents the value
|
|
|
1104 |
of the current field.
|
|
|
1105 |
|
|
|
1106 |
If the value is a function, it will be assumed to be a formatting function.
|
|
|
1107 |
A formatting function receives a single argument, an object with the following properties:
|
|
|
1108 |
|
|
|
1109 |
* __value__ The raw value from the record Model to populate this cell.
|
|
|
1110 |
Equivalent to `o.record.get(o.column.key)` or `o.data[o.column.key]`.
|
|
|
1111 |
* __data__ The Model data for this row in simple object format.
|
|
|
1112 |
* __record__ The Model for this row.
|
|
|
1113 |
* __column__ The column configuration object.
|
|
|
1114 |
* __className__ A string of class names to add `<td class="HERE">` in addition to
|
|
|
1115 |
the column class and any classes in the column's className configuration.
|
|
|
1116 |
* __rowIndex__ The index of the current Model in the ModelList.
|
|
|
1117 |
Typically correlates to the row index as well.
|
|
|
1118 |
* __rowClass__ A string of css classes to add `<tr class="HERE"><td....`
|
|
|
1119 |
This is useful to avoid the need for nodeFormatters to add classes to the containing row.
|
|
|
1120 |
|
|
|
1121 |
The formatter function may return a string value that will be used for the cell
|
|
|
1122 |
contents or it may change the value of the `value`, `className` or `rowClass`
|
|
|
1123 |
properties which well then be used to format the cell. If the value for the cell
|
|
|
1124 |
is returned in the `value` property of the input argument, no value should be returned.
|
|
|
1125 |
|
|
|
1126 |
{
|
|
|
1127 |
key: 'name',
|
|
|
1128 |
formatter: 'link', // named formatter
|
|
|
1129 |
linkFrom: 'website' // extra column property for link formatter
|
|
|
1130 |
},
|
|
|
1131 |
{
|
|
|
1132 |
key: 'cost',
|
|
|
1133 |
formatter: '${value}' // formatter template string
|
|
|
1134 |
//formatter: '${cost}' // same result but less portable
|
|
|
1135 |
},
|
|
|
1136 |
{
|
|
|
1137 |
name: 'Name', // column does not have associated field value
|
|
|
1138 |
// thus, it uses name instead of key
|
|
|
1139 |
formatter: '{firstName} {lastName}' // template references other fields
|
|
|
1140 |
},
|
|
|
1141 |
{
|
|
|
1142 |
key: 'price',
|
|
|
1143 |
formatter: function (o) { // function both returns a string to show
|
|
|
1144 |
if (o.value > 3) { // and a className to apply to the cell
|
|
|
1145 |
o.className += 'expensive';
|
|
|
1146 |
}
|
|
|
1147 |
|
|
|
1148 |
return '$' + o.value.toFixed(2);
|
|
|
1149 |
}
|
|
|
1150 |
},
|
|
|
1151 |
@property formatter
|
|
|
1152 |
@type String || Function
|
|
|
1153 |
|
|
|
1154 |
*/
|
|
|
1155 |
/**
|
|
|
1156 |
Used to customize the content of the data cells for this column.
|
|
|
1157 |
|
|
|
1158 |
`nodeFormatter` is significantly slower than [formatter](#property_formatter)
|
|
|
1159 |
and should be avoided if possible. Unlike [formatter](#property_formatter),
|
|
|
1160 |
`nodeFormatter` has access to the `<td>` element and its ancestors.
|
|
|
1161 |
|
|
|
1162 |
The function provided is expected to fill in the `<td>` element itself.
|
|
|
1163 |
__Node formatters should return `false`__ except in certain conditions as described
|
|
|
1164 |
in the users guide.
|
|
|
1165 |
|
|
|
1166 |
The function receives a single object
|
|
|
1167 |
argument with the following properties:
|
|
|
1168 |
|
|
|
1169 |
* __td__ The `<td>` Node for this cell.
|
|
|
1170 |
* __cell__ If the cell `<td> contains an element with class `yui3-datatable-liner,
|
|
|
1171 |
this will refer to that Node. Otherwise, it is equivalent to `td` (default behavior).
|
|
|
1172 |
* __value__ The raw value from the record Model to populate this cell.
|
|
|
1173 |
Equivalent to `o.record.get(o.column.key)` or `o.data[o.column.key]`.
|
|
|
1174 |
* __data__ The Model data for this row in simple object format.
|
|
|
1175 |
* __record__ The Model for this row.
|
|
|
1176 |
* __column__ The column configuration object.
|
|
|
1177 |
* __rowIndex__ The index of the current Model in the ModelList.
|
|
|
1178 |
_Typically_ correlates to the row index as well.
|
|
|
1179 |
|
|
|
1180 |
@example
|
|
|
1181 |
nodeFormatter: function (o) {
|
|
|
1182 |
if (o.value < o.data.quota) {
|
|
|
1183 |
o.td.setAttribute('rowspan', 2);
|
|
|
1184 |
o.td.setAttribute('data-term-id', this.record.get('id'));
|
|
|
1185 |
|
|
|
1186 |
o.td.ancestor().insert(
|
|
|
1187 |
'<tr><td colspan"3">' +
|
|
|
1188 |
'<button class="term">terminate</button>' +
|
|
|
1189 |
'</td></tr>',
|
|
|
1190 |
'after');
|
|
|
1191 |
}
|
|
|
1192 |
|
|
|
1193 |
o.cell.setHTML(o.value);
|
|
|
1194 |
return false;
|
|
|
1195 |
}
|
|
|
1196 |
|
|
|
1197 |
@property nodeFormatter
|
|
|
1198 |
@type Function
|
|
|
1199 |
*/
|
|
|
1200 |
/**
|
|
|
1201 |
Provides the default value to populate the cell if the data
|
|
|
1202 |
for that cell is `undefined`, `null`, or an empty string.
|
|
|
1203 |
|
|
|
1204 |
{
|
|
|
1205 |
key: 'price',
|
|
|
1206 |
emptyCellValue: '???'
|
|
|
1207 |
}
|
|
|
1208 |
|
|
|
1209 |
@property emptyCellValue
|
|
|
1210 |
@type {String} depending on the setting of allowHTML
|
|
|
1211 |
*/
|
|
|
1212 |
/**
|
|
|
1213 |
Skips the security step of HTML escaping the value for cells
|
|
|
1214 |
in this column.
|
|
|
1215 |
|
|
|
1216 |
This is also necessary if [emptyCellValue](#property_emptyCellValue)
|
|
|
1217 |
is set with an HTML string.
|
|
|
1218 |
`nodeFormatter`s ignore this configuration. If using a
|
|
|
1219 |
`nodeFormatter`, it is recommended to use
|
|
|
1220 |
[Y.Escape.html()](Escape.html#method_html)
|
|
|
1221 |
on any user supplied content that is to be displayed.
|
|
|
1222 |
|
|
|
1223 |
{
|
|
|
1224 |
key: 'preview',
|
|
|
1225 |
allowHTML: true
|
|
|
1226 |
}
|
|
|
1227 |
|
|
|
1228 |
@property allowHTML
|
|
|
1229 |
@type Boolean
|
|
|
1230 |
*/
|
|
|
1231 |
/**
|
|
|
1232 |
A string of CSS classes that will be added to the `<td>`'s
|
|
|
1233 |
`class` attribute.
|
|
|
1234 |
|
|
|
1235 |
Note, all cells will automatically have a class in the
|
|
|
1236 |
form of "yui3-datatable-col-XXX" added to the `<td>`, where
|
|
|
1237 |
XXX is the column's configured `name`, `key`, or `id` (in
|
|
|
1238 |
that order of preference) sanitized from invalid characters.
|
|
|
1239 |
|
|
|
1240 |
{
|
|
|
1241 |
key: 'symbol',
|
|
|
1242 |
className: 'no-hide'
|
|
|
1243 |
}
|
|
|
1244 |
|
|
|
1245 |
@property className
|
|
|
1246 |
@type String
|
|
|
1247 |
*/
|
|
|
1248 |
/**
|
|
|
1249 |
(__read-only__) The unique identifier assigned
|
|
|
1250 |
to each column. This is used for the `id` if not set, and
|
|
|
1251 |
the `_id` if none of [name](#property_name),
|
|
|
1252 |
[field](#property_field), [key](#property_key), or [id](#property_id) are
|
|
|
1253 |
set.
|
|
|
1254 |
|
|
|
1255 |
@property _yuid
|
|
|
1256 |
@type String
|
|
|
1257 |
@protected
|
|
|
1258 |
*/
|
|
|
1259 |
/**
|
|
|
1260 |
(__read-only__) A unique-to-this-instance name
|
|
|
1261 |
used extensively in the rendering process. It is also used
|
|
|
1262 |
to create the column's classname, as the input name
|
|
|
1263 |
`table.getColumn(HERE)`, and in the column header's
|
|
|
1264 |
`<th data-yui3-col-id="HERE">`.
|
|
|
1265 |
|
|
|
1266 |
The value is populated by the first of [name](#property_name),
|
|
|
1267 |
[field](#property_field), [key](#property_key), [id](#property_id),
|
|
|
1268 |
or [_yuid](#property__yuid) to have a value. If that value
|
|
|
1269 |
has already been used (such as when multiple columns have
|
|
|
1270 |
the same `key`), an incrementer is added to the end. For
|
|
|
1271 |
example, two columns with `key: "id"` will have `_id`s of
|
|
|
1272 |
"id" and "id2". `table.getColumn("id")` will return the
|
|
|
1273 |
first column, and `table.getColumn("id2")` will return the
|
|
|
1274 |
second.
|
|
|
1275 |
|
|
|
1276 |
@property _id
|
|
|
1277 |
@type String
|
|
|
1278 |
@protected
|
|
|
1279 |
*/
|
|
|
1280 |
/**
|
|
|
1281 |
(__read-only__) Used by
|
|
|
1282 |
`Y.DataTable.HeaderView` when building stacked column
|
|
|
1283 |
headers.
|
|
|
1284 |
|
|
|
1285 |
@property _colspan
|
|
|
1286 |
@type Integer
|
|
|
1287 |
@protected
|
|
|
1288 |
*/
|
|
|
1289 |
/**
|
|
|
1290 |
(__read-only__) Used by
|
|
|
1291 |
`Y.DataTable.HeaderView` when building stacked column
|
|
|
1292 |
headers.
|
|
|
1293 |
|
|
|
1294 |
@property _rowspan
|
|
|
1295 |
@type Integer
|
|
|
1296 |
@protected
|
|
|
1297 |
*/
|
|
|
1298 |
/**
|
|
|
1299 |
(__read-only__) Assigned to all columns in a
|
|
|
1300 |
column's `children` collection. References the parent
|
|
|
1301 |
column object.
|
|
|
1302 |
|
|
|
1303 |
@property _parent
|
|
|
1304 |
@type DataTable.Column
|
|
|
1305 |
@protected
|
|
|
1306 |
*/
|
|
|
1307 |
/**
|
|
|
1308 |
(__read-only__) Array of the `id`s of the
|
|
|
1309 |
column and all parent columns. Used by
|
|
|
1310 |
`Y.DataTable.BodyView` to populate `<td headers="THIS">`
|
|
|
1311 |
when a cell references more than one header.
|
|
|
1312 |
|
|
|
1313 |
@property _headers
|
|
|
1314 |
@type Array
|
|
|
1315 |
@protected
|
|
|
1316 |
*/
|
|
|
1317 |
|
|
|
1318 |
|
|
|
1319 |
}, '3.18.1', {"requires": ["escape", "model-list", "node-event-delegate"]});
|