Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('datatable-mutable', function (Y, NAME) {
2
 
3
/**
4
Adds mutation convenience methods such as `table.addRow(data)` to `Y.DataTable`. (or other built class).
5
 
6
@module datatable
7
@submodule datatable-mutable
8
@since 3.5.0
9
**/
10
var toArray = Y.Array,
11
    YLang   = Y.Lang,
12
    isString = YLang.isString,
13
    isArray  = YLang.isArray,
14
    isObject = YLang.isObject,
15
    isNumber = YLang.isNumber,
16
    arrayIndex = Y.Array.indexOf,
17
    Mutable;
18
 
19
/**
20
_API docs for this extension are included in the DataTable class._
21
 
22
Class extension to add mutation convenience methods to `Y.DataTable` (or other
23
built class).
24
 
25
Column mutation methods are paired with new custom events:
26
 
27
 * addColumn
28
 * removeColumn
29
 * modifyColumn
30
 * moveColumn
31
 
32
Row mutation events are bubbled from the DataTable's `data` ModelList through
33
the DataTable instance.
34
 
35
@class DataTable.Mutable
36
@for DataTable
37
@since 3.5.0
38
**/
39
Y.namespace('DataTable').Mutable = Mutable = function () {};
40
 
41
Mutable.ATTRS = {
42
    /**
43
    Controls whether `addRow`, `removeRow`, and `modifyRow` should trigger the
44
    underlying Model's sync layer by default.
45
 
46
    When `true`, it is unnecessary to pass the "sync" configuration property to
47
    those methods to trigger per-operation sync.
48
 
49
 
50
    @attribute autoSync
51
    @type {Boolean}
52
    @default `false`
53
    @since 3.5.0
54
    **/
55
    autoSync: {
56
        value: false,
57
        validator: YLang.isBoolean
58
    }
59
};
60
 
61
Y.mix(Mutable.prototype, {
62
    /**
63
    Adds the column configuration to the DataTable's `columns` configuration.
64
    If the `index` parameter is supplied, it is injected at that index.  If the
65
    table has nested headers, inject a subcolumn by passing an array of indexes
66
    to identify the new column's final location.
67
 
68
    The `index` parameter is required if adding a nested column.
69
 
70
    This method is a convienience method for fetching the DataTable's `columns`
71
    attribute, updating it, and calling
72
    `table.set('columns', _updatedColumnsDefs_)`
73
 
74
    For example:
75
 
76
    <pre><code>// Becomes last column
77
    table.addColumn('name');
78
 
79
    // Inserted after the current second column, moving the current third column
80
    // to index 4
81
    table.addColumn({ key: 'price', formatter: currencyFormatter }, 2 );
82
 
83
    // Insert a new column in a set of headers three rows deep.  The index array
84
    // translates to
85
    // [ 2, --  in the third column's children
86
    //   1, --  in the second child's children
87
    //   3 ] -- as the fourth child column
88
    table.addColumn({ key: 'age', sortable: true }, [ 2, 1, 3 ]);
89
    </code></pre>
90
 
91
    @method addColumn
92
    @param {Object|String} config The new column configuration object
93
    @param {Number|Number[]} [index] the insertion index
94
    @return {DataTable}
95
    @chainable
96
    @since 3.5.0
97
    **/
98
    addColumn: function (config, index) {
99
        if (isString(config)) {
100
            config = { key: config };
101
        }
102
 
103
        if (config) {
104
            if (arguments.length < 2 || (!isNumber(index) && !isArray(index))) {
105
                index = this.get('columns').length;
106
            }
107
 
108
            this.fire('addColumn', {
109
                column: config,
110
                index: index
111
            });
112
        }
113
        return this;
114
    },
115
 
116
    /**
117
    Updates an existing column definition. Fires the `modifyColumn` event.
118
 
119
    For example:
120
 
121
    <pre><code>// Add a formatter to the existing 'price' column definition
122
    table.modifyColumn('price', { formatter: currencyFormatter });
123
 
124
    // Change the label on a header cell in a set of nested headers three rows
125
    // deep.  The index array translates to
126
    // [ 2,  -- in the third column's children
127
    //   1,  -- the second child
128
    //   3 ] -- the fourth child column
129
    table.modifyColumn([2, 1, 3], { label: 'Experience' });
130
    </code></pre>
131
 
132
    @method modifyColumn
133
    @param {String|Number|Number[]|Object} name The column key, name, index, or
134
                current configuration object
135
    @param {Object} config The new column configuration properties
136
    @return {DataTable}
137
    @chainable
138
    @since 3.5.0
139
    **/
140
    modifyColumn: function (name, config) {
141
        if (isString(config)) {
142
            config = { key: config };
143
        }
144
 
145
        if (isObject(config)) {
146
            this.fire('modifyColumn', {
147
                column: name,
148
                newColumnDef: config
149
            });
150
        }
151
 
152
        return this;
153
    },
154
 
155
    /**
156
    Moves an existing column to a new location. Fires the `moveColumn` event.
157
 
158
    The destination index can be a number or array of numbers to place a column
159
    header in a nested header row.
160
 
161
    @method moveColumn
162
    @param {String|Number|Number[]|Object} name The column key, name, index, or
163
                current configuration object
164
    @param {Number|Number[]} index The destination index of the column
165
    @return {DataTable}
166
    @chainable
167
    @since 3.5.0
168
    **/
169
    moveColumn: function (name, index) {
170
        if (name !== undefined && (isNumber(index) || isArray(index))) {
171
            this.fire('moveColumn', {
172
                column: name,
173
                index: index
174
            });
175
        }
176
 
177
        return this;
178
    },
179
 
180
    /**
181
    Removes an existing column. Fires the `removeColumn` event.
182
 
183
    @method removeColumn
184
    @param {String|Number|Number[]|Object} name The column key, name, index, or
185
                current configuration object
186
    @return {DataTable}
187
    @chainable
188
    @since 3.5.0
189
    **/
190
    removeColumn: function (name) {
191
        if (name !== undefined) {
192
            this.fire('removeColumn', {
193
                column: name
194
            });
195
        }
196
 
197
        return this;
198
    },
199
 
200
    /**
201
    Adds a new record to the DataTable's `data` ModelList.  Record data can be
202
    an object of field values or an instance of the DataTable's configured
203
    `recordType` class.
204
 
205
    This relays all parameters to the `data` ModelList's `add` method.
206
 
207
    If a configuration object is passed as a second argument, and that object
208
    has `sync: true` set, the underlying Model will be `save()`d.
209
 
210
    If the DataTable's `autoSync` attribute is set to `true`, the additional
211
    argument is not needed.
212
 
213
    If syncing and the last argument is a function, that function will be used
214
    as a callback to the Model's `save()` method.
215
 
216
    @method addRow
217
    @param {Object} data The data or Model instance for the new record
218
    @param {Object} [config] Configuration to pass along
219
    @param {Function} [callback] Callback function for Model's `save()`
220
      @param {Error|null} callback.err If an error occurred or validation
221
        failed, this parameter will contain the error. If the sync operation
222
        succeeded, _err_ will be `null`.
223
      @param {Any} callback.response The server's response. This value will
224
        be passed to the `parse()` method, which is expected to parse it and
225
        return an attribute hash.
226
    @return {DataTable}
227
    @chainable
228
    @since 3.5.0
229
    **/
230
    addRow: function (data, config) {
231
        // Allow autoSync: true + addRow({ data }, { sync: false })
232
        var sync = (config && ('sync' in config)) ?
233
                config.sync :
234
                this.get('autoSync'),
235
            models, model, i, len, args;
236
 
237
        if (data && this.data) {
238
            models = this.data.add.apply(this.data, arguments);
239
 
240
            if (sync) {
241
                models = toArray(models);
242
                args   = toArray(arguments, 1, true);
243
 
244
                for (i = 0, len = models.length; i < len; ++i) {
245
                    model = models[i];
246
 
247
                    if (model.isNew()) {
248
                        models[i].save.apply(models[i], args);
249
                    }
250
                }
251
            }
252
        }
253
 
254
        return this;
255
    },
256
 
257
    /**
258
    Removes a record from the DataTable's `data` ModelList.  The record can be
259
    provided explicitly or targeted by it's `id` (see ModelList's `getById`
260
    method), `clientId`, or index in the ModelList.
261
 
262
    After locating the target Model, this relays the Model and all other passed
263
    arguments to the `data` ModelList's `remove` method.
264
 
265
    If a configuration object is passed as a second argument, and that object
266
    has `sync: true` set, the underlying Model will be destroyed, passing
267
    `{ delete: true }` to trigger calling the Model's sync layer.
268
 
269
    If the DataTable's `autoSync` attribute is set to `true`, the additional
270
    argument is not needed.
271
 
272
    If syncing and the last argument is a function, that function will be used
273
    as a callback to the Model's `destroy()` method.
274
 
275
    @method removeRow
276
    @param {Object|String|Number} id The Model instance or identifier
277
    @param {Object} [config] Configuration to pass along
278
    @param {Function} [callback] Callback function for Model's `save()`
279
      @param {Error|null} callback.err If an error occurred or validation
280
        failed, this parameter will contain the error. If the sync operation
281
        succeeded, _err_ will be `null`.
282
      @param {Any} callback.response The server's response. This value will
283
        be passed to the `parse()` method, which is expected to parse it and
284
        return an attribute hash.
285
    @return {DataTable}
286
    @chainable
287
    @since 3.5.0
288
    **/
289
    removeRow: function (id, config) {
290
        var modelList = this.data,
291
            // Allow autoSync: true + addRow({ data }, { sync: false })
292
            sync      = (config && ('sync' in config)) ?
293
                            config.sync :
294
                            this.get('autoSync'),
295
            models, model, i, len, args;
296
 
297
        // TODO: support removing via DOM element. This should be relayed to View
298
        if (isObject(id) && id instanceof this.get('recordType')) {
299
            model = id;
300
        } else if (modelList && id !== undefined) {
301
            model = modelList.getById(id) ||
302
                    modelList.getByClientId(id) ||
303
                    modelList.item(id);
304
        }
305
 
306
        if (model) {
307
            args = toArray(arguments, 1, true);
308
 
309
            models = modelList.remove.apply(modelList,
310
                [model].concat(args));
311
 
312
            if (sync) {
313
                if (!isObject(args[0])) {
314
                    args.unshift({});
315
                }
316
 
317
                args[0]['delete'] = true;
318
 
319
                models = toArray(models);
320
 
321
                for (i = 0, len = models.length; i < len; ++i) {
322
                    model = models[i];
323
                    model.destroy.apply(model, args);
324
                }
325
            }
326
        }
327
 
328
        return this;
329
    },
330
 
331
    /**
332
    Updates an existing record in the DataTable's `data` ModelList.  The record
333
    can be provided explicitly or targeted by it's `id` (see ModelList's
334
    `getById` method), `clientId`, or index in the ModelList.
335
 
336
    After locating the target Model, this relays the all other passed
337
    arguments to the Model's `setAttrs` method.
338
 
339
    If a configuration object is passed as a second argument, and that object
340
    has `sync: true` set, the underlying Model will be `save()`d.
341
 
342
    If the DataTable's `autoSync` attribute is set to `true`, the additional
343
    argument is not needed.
344
 
345
    If syncing and the last argument is a function, that function will be used
346
    as a callback to the Model's `save()` method.
347
 
348
    @method modifyRow
349
    @param {Object|String|Number} id The Model instance or identifier
350
    @param {Object} data New data values for the Model
351
    @param {Object} [config] Configuration to pass along to `setAttrs()`
352
    @param {Function} [callback] Callback function for Model's `save()`
353
      @param {Error|null} callback.err If an error occurred or validation
354
        failed, this parameter will contain the error. If the sync operation
355
        succeeded, _err_ will be `null`.
356
      @param {Any} callback.response The server's response. This value will
357
        be passed to the `parse()` method, which is expected to parse it and
358
        return an attribute hash.
359
    @return {DataTable}
360
    @chainable
361
    @since 3.5.0
362
    **/
363
    modifyRow: function (id, data, config) {
364
        var modelList = this.data,
365
            // Allow autoSync: true + addRow({ data }, { sync: false })
366
            sync      = (config && ('sync' in config)) ?
367
                            config.sync :
368
                            this.get('autoSync'),
369
            model, args;
370
 
371
        if (isObject(id) && id instanceof this.get('recordType')) {
372
            model = id;
373
        } else if (modelList && id !== undefined) {
374
            model = modelList.getById(id) ||
375
                    modelList.getByClientId(id) ||
376
                    modelList.item(id);
377
        }
378
 
379
        if (model && isObject(data)) {
380
            args = toArray(arguments, 1, true);
381
 
382
            model.setAttrs.apply(model, args);
383
 
384
            if (sync && !model.isNew()) {
385
                model.save.apply(model, args);
386
            }
387
        }
388
 
389
        return this;
390
    },
391
 
392
    // --------------------------------------------------------------------------
393
    // Protected properties and methods
394
    // --------------------------------------------------------------------------
395
 
396
    /**
397
    Default function for the `addColumn` event.
398
 
399
    Inserts the specified column at the provided index.
400
 
401
    @method _defAddColumnFn
402
    @param {EventFacade} e The `addColumn` event
403
        @param {Object} e.column The new column definition object
404
        @param {Number|Number[]} e.index The array index to insert the new column
405
    @protected
406
    @since 3.5.0
407
    **/
408
    _defAddColumnFn: function (e) {
409
        var index   = toArray(e.index),
410
            columns = this.get('columns'),
411
            cols    = columns,
412
            i, len;
413
 
414
        for (i = 0, len = index.length - 1; cols && i < len; ++i) {
415
            cols = cols[index[i]] && cols[index[i]].children;
416
        }
417
 
418
        if (cols) {
419
            cols.splice(index[i], 0, e.column);
420
 
421
            this.set('columns', columns, { originEvent: e });
422
        } else { Y.log('addColumn index not findable', 'warn', 'datatable');
423
        }
424
    },
425
 
426
    /**
427
    Default function for the `modifyColumn` event.
428
 
429
    Mixes the new column properties into the specified column definition.
430
 
431
    @method _defModifyColumnFn
432
    @param {EventFacade} e The `modifyColumn` event
433
        @param {Object|String|Number|Number[]} e.column The column definition object or identifier
434
        @param {Object} e.newColumnDef The properties to assign to the column
435
    @protected
436
    @since 3.5.0
437
    **/
438
    _defModifyColumnFn: function (e) {
439
        var columns = this.get('columns'),
440
            column  = this.getColumn(e.column);
441
 
442
        if (column) {
443
            Y.mix(column, e.newColumnDef, true);
444
 
445
            this.set('columns', columns, { originEvent: e });
446
        } else { Y.log('Could not locate column index to modify column', 'warn', 'datatable');
447
        }
448
    },
449
 
450
    /**
451
    Default function for the `moveColumn` event.
452
 
453
    Removes the specified column from its current location and inserts it at the
454
    specified array index (may be an array of indexes for nested headers).
455
 
456
    @method _defMoveColumnFn
457
    @param {EventFacade} e The `moveColumn` event
458
        @param {Object|String|Number|Number[]} e.column The column definition object or identifier
459
        @param {Object} e.index The destination index to move to
460
    @protected
461
    @since 3.5.0
462
    **/
463
    _defMoveColumnFn: function (e) {
464
        var columns = this.get('columns'),
465
            column  = this.getColumn(e.column),
466
            toIndex = toArray(e.index),
467
            fromCols, fromIndex, toCols, i, len;
468
 
469
        if (column) {
470
            fromCols  = column._parent ? column._parent.children : columns;
471
            fromIndex = arrayIndex(fromCols, column);
472
 
473
            if (fromIndex > -1) {
474
                toCols = columns;
475
 
476
                for (i = 0, len = toIndex.length - 1; toCols && i < len; ++i) {
477
                    toCols = toCols[toIndex[i]] && toCols[toIndex[i]].children;
478
                }
479
 
480
                if (toCols) {
481
                    len = toCols.length;
482
                    fromCols.splice(fromIndex, 1);
483
                    toIndex = toIndex[i];
484
 
485
                    if (len > toCols.lenth) {
486
                        // spliced off the same array, so adjust destination
487
                        // index if necessary
488
                        if (fromIndex < toIndex) {
489
                            toIndex--;
490
                        }
491
                    }
492
 
493
                    toCols.splice(toIndex, 0, column);
494
 
495
                    this.set('columns', columns, { originEvent: e });
496
                } else { Y.log('Column [' + e.column + '] could not be moved. Destination index invalid for moveColumn', 'warn', 'datatable');
497
                }
498
            }
499
        } else { Y.log('Column [' + e.column + '] not found for moveColumn', 'warn', 'datatable');
500
        }
501
    },
502
 
503
    /**
504
    Default function for the `removeColumn` event.
505
 
506
    Splices the specified column from its containing columns array.
507
 
508
    @method _defRemoveColumnFn
509
    @param {EventFacade} e The `removeColumn` event
510
        @param {Object|String|Number|Number[]} e.column The column definition object or identifier
511
    @protected
512
    @since 3.5.0
513
    **/
514
    _defRemoveColumnFn: function (e) {
515
        var columns = this.get('columns'),
516
            column  = this.getColumn(e.column),
517
            cols, index;
518
 
519
        if (column) {
520
            cols = column._parent ? column._parent.children : columns;
521
            index = Y.Array.indexOf(cols, column);
522
 
523
            if (index > -1) {
524
                cols.splice(index, 1);
525
 
526
                this.set('columns', columns, { originEvent: e });
527
            }
528
        } else { Y.log('Could not locate column [' + e.column + '] for removeColumn', 'warn', 'datatable');
529
        }
530
    },
531
 
532
    /**
533
    Publishes the events used by the mutation methods:
534
 
535
     * addColumn
536
     * removeColumn
537
     * modifyColumn
538
     * moveColumn
539
 
540
    @method initializer
541
    @protected
542
    @since 3.5.0
543
    **/
544
    initializer: function () {
545
        this.publish({
546
            addColumn:    { defaultFn: Y.bind('_defAddColumnFn', this) },
547
            removeColumn: { defaultFn: Y.bind('_defRemoveColumnFn', this) },
548
            moveColumn:   { defaultFn: Y.bind('_defMoveColumnFn', this) },
549
            modifyColumn: { defaultFn: Y.bind('_defModifyColumnFn', this) }
550
        });
551
    }
552
});
553
 
554
/**
555
Adds an array of new records to the DataTable's `data` ModelList.  Record data
556
can be an array of objects containing field values or an array of instance of
557
the DataTable's configured `recordType` class.
558
 
559
This relays all parameters to the `data` ModelList's `add` method.
560
 
561
Technically, this is an alias to `addRow`, but please use the appropriately
562
named method for readability.
563
 
564
If a configuration object is passed as a second argument, and that object
565
has `sync: true` set, the underlying Models will be `save()`d.
566
 
567
If the DataTable's `autoSync` attribute is set to `true`, the additional
568
argument is not needed.
569
 
570
If syncing and the last argument is a function, that function will be used
571
as a callback to each Model's `save()` method.
572
 
573
@method addRows
574
@param {Object[]} data The data or Model instances to add
575
@param {Object} [config] Configuration to pass along
576
@param {Function} [callback] Callback function for each Model's `save()`
577
  @param {Error|null} callback.err If an error occurred or validation
578
    failed, this parameter will contain the error. If the sync operation
579
    succeeded, _err_ will be `null`.
580
  @param {Any} callback.response The server's response. This value will
581
    be passed to the `parse()` method, which is expected to parse it and
582
    return an attribute hash.
583
@return {DataTable}
584
@chainable
585
@since 3.5.0
586
**/
587
Mutable.prototype.addRows = Mutable.prototype.addRow;
588
 
589
// Add feature APIs to public Y.DataTable class
590
if (YLang.isFunction(Y.DataTable)) {
591
    Y.Base.mix(Y.DataTable, [Mutable]);
592
}
593
 
594
/**
595
Fired by the `addColumn` method.
596
 
597
@event addColumn
598
@preventable _defAddColumnFn
599
@param {Object} column The new column definition object
600
@param {Number|Number[]} index The array index to insert the new column
601
@since 3.5.0
602
**/
603
 
604
/**
605
Fired by the `removeColumn` method.
606
 
607
@event removeColumn
608
@preventable _defRemoveColumnFn
609
@param {Object|String|Number|Number[]} column The column definition object or identifier
610
@since 3.5.0
611
**/
612
 
613
/**
614
Fired by the `modifyColumn` method.
615
 
616
@event modifyColumn
617
@preventable _defModifyColumnFn
618
@param {Object|String|Number|Number[]} column The column definition object or identifier
619
@param {Object} newColumnDef The properties to assign to the column
620
@since 3.5.0
621
**/
622
 
623
/**
624
Fired by the `moveColumn` method.
625
 
626
@event moveColumn
627
@preventable _defMoveColumnFn
628
@param {Object|String|Number|Number[]} column The column definition object or identifier
629
@param {Object} index The destination index to move to
630
@since 3.5.0
631
**/
632
 
633
 
634
 
635
}, '3.18.1', {"requires": ["datatable-base"]});