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
        }
423
    },
424
 
425
    /**
426
    Default function for the `modifyColumn` event.
427
 
428
    Mixes the new column properties into the specified column definition.
429
 
430
    @method _defModifyColumnFn
431
    @param {EventFacade} e The `modifyColumn` event
432
        @param {Object|String|Number|Number[]} e.column The column definition object or identifier
433
        @param {Object} e.newColumnDef The properties to assign to the column
434
    @protected
435
    @since 3.5.0
436
    **/
437
    _defModifyColumnFn: function (e) {
438
        var columns = this.get('columns'),
439
            column  = this.getColumn(e.column);
440
 
441
        if (column) {
442
            Y.mix(column, e.newColumnDef, true);
443
 
444
            this.set('columns', columns, { originEvent: e });
445
        }
446
    },
447
 
448
    /**
449
    Default function for the `moveColumn` event.
450
 
451
    Removes the specified column from its current location and inserts it at the
452
    specified array index (may be an array of indexes for nested headers).
453
 
454
    @method _defMoveColumnFn
455
    @param {EventFacade} e The `moveColumn` event
456
        @param {Object|String|Number|Number[]} e.column The column definition object or identifier
457
        @param {Object} e.index The destination index to move to
458
    @protected
459
    @since 3.5.0
460
    **/
461
    _defMoveColumnFn: function (e) {
462
        var columns = this.get('columns'),
463
            column  = this.getColumn(e.column),
464
            toIndex = toArray(e.index),
465
            fromCols, fromIndex, toCols, i, len;
466
 
467
        if (column) {
468
            fromCols  = column._parent ? column._parent.children : columns;
469
            fromIndex = arrayIndex(fromCols, column);
470
 
471
            if (fromIndex > -1) {
472
                toCols = columns;
473
 
474
                for (i = 0, len = toIndex.length - 1; toCols && i < len; ++i) {
475
                    toCols = toCols[toIndex[i]] && toCols[toIndex[i]].children;
476
                }
477
 
478
                if (toCols) {
479
                    len = toCols.length;
480
                    fromCols.splice(fromIndex, 1);
481
                    toIndex = toIndex[i];
482
 
483
                    if (len > toCols.lenth) {
484
                        // spliced off the same array, so adjust destination
485
                        // index if necessary
486
                        if (fromIndex < toIndex) {
487
                            toIndex--;
488
                        }
489
                    }
490
 
491
                    toCols.splice(toIndex, 0, column);
492
 
493
                    this.set('columns', columns, { originEvent: e });
494
                }
495
            }
496
        }
497
    },
498
 
499
    /**
500
    Default function for the `removeColumn` event.
501
 
502
    Splices the specified column from its containing columns array.
503
 
504
    @method _defRemoveColumnFn
505
    @param {EventFacade} e The `removeColumn` event
506
        @param {Object|String|Number|Number[]} e.column The column definition object or identifier
507
    @protected
508
    @since 3.5.0
509
    **/
510
    _defRemoveColumnFn: function (e) {
511
        var columns = this.get('columns'),
512
            column  = this.getColumn(e.column),
513
            cols, index;
514
 
515
        if (column) {
516
            cols = column._parent ? column._parent.children : columns;
517
            index = Y.Array.indexOf(cols, column);
518
 
519
            if (index > -1) {
520
                cols.splice(index, 1);
521
 
522
                this.set('columns', columns, { originEvent: e });
523
            }
524
        }
525
    },
526
 
527
    /**
528
    Publishes the events used by the mutation methods:
529
 
530
     * addColumn
531
     * removeColumn
532
     * modifyColumn
533
     * moveColumn
534
 
535
    @method initializer
536
    @protected
537
    @since 3.5.0
538
    **/
539
    initializer: function () {
540
        this.publish({
541
            addColumn:    { defaultFn: Y.bind('_defAddColumnFn', this) },
542
            removeColumn: { defaultFn: Y.bind('_defRemoveColumnFn', this) },
543
            moveColumn:   { defaultFn: Y.bind('_defMoveColumnFn', this) },
544
            modifyColumn: { defaultFn: Y.bind('_defModifyColumnFn', this) }
545
        });
546
    }
547
});
548
 
549
/**
550
Adds an array of new records to the DataTable's `data` ModelList.  Record data
551
can be an array of objects containing field values or an array of instance of
552
the DataTable's configured `recordType` class.
553
 
554
This relays all parameters to the `data` ModelList's `add` method.
555
 
556
Technically, this is an alias to `addRow`, but please use the appropriately
557
named method for readability.
558
 
559
If a configuration object is passed as a second argument, and that object
560
has `sync: true` set, the underlying Models will be `save()`d.
561
 
562
If the DataTable's `autoSync` attribute is set to `true`, the additional
563
argument is not needed.
564
 
565
If syncing and the last argument is a function, that function will be used
566
as a callback to each Model's `save()` method.
567
 
568
@method addRows
569
@param {Object[]} data The data or Model instances to add
570
@param {Object} [config] Configuration to pass along
571
@param {Function} [callback] Callback function for each Model's `save()`
572
  @param {Error|null} callback.err If an error occurred or validation
573
    failed, this parameter will contain the error. If the sync operation
574
    succeeded, _err_ will be `null`.
575
  @param {Any} callback.response The server's response. This value will
576
    be passed to the `parse()` method, which is expected to parse it and
577
    return an attribute hash.
578
@return {DataTable}
579
@chainable
580
@since 3.5.0
581
**/
582
Mutable.prototype.addRows = Mutable.prototype.addRow;
583
 
584
// Add feature APIs to public Y.DataTable class
585
if (YLang.isFunction(Y.DataTable)) {
586
    Y.Base.mix(Y.DataTable, [Mutable]);
587
}
588
 
589
/**
590
Fired by the `addColumn` method.
591
 
592
@event addColumn
593
@preventable _defAddColumnFn
594
@param {Object} column The new column definition object
595
@param {Number|Number[]} index The array index to insert the new column
596
@since 3.5.0
597
**/
598
 
599
/**
600
Fired by the `removeColumn` method.
601
 
602
@event removeColumn
603
@preventable _defRemoveColumnFn
604
@param {Object|String|Number|Number[]} column The column definition object or identifier
605
@since 3.5.0
606
**/
607
 
608
/**
609
Fired by the `modifyColumn` method.
610
 
611
@event modifyColumn
612
@preventable _defModifyColumnFn
613
@param {Object|String|Number|Number[]} column The column definition object or identifier
614
@param {Object} newColumnDef The properties to assign to the column
615
@since 3.5.0
616
**/
617
 
618
/**
619
Fired by the `moveColumn` method.
620
 
621
@event moveColumn
622
@preventable _defMoveColumnFn
623
@param {Object|String|Number|Number[]} column The column definition object or identifier
624
@param {Object} index The destination index to move to
625
@since 3.5.0
626
**/
627
 
628
 
629
 
630
}, '3.18.1', {"requires": ["datatable-base"]});