Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
H5PEditor.List = (function ($) {
2
  /**
3
   * List structure.
4
   *
5
   * @class
6
   * @param {*} parent structure
7
   * @param {Object} field Semantic description of field
8
   * @param {Array} [parameters] Default parameters for this field
9
   * @param {Function} setValue Call to set our parameters
10
   */
11
  function List(parent, field, parameters, setValue) {
12
    var self = this;
13
 
14
    // Initialize semantics structure inheritance
15
    H5PEditor.SemanticStructure.call(self, field, {
16
      name: 'ListEditor',
17
      label: H5PEditor.t('core', 'listLabel')
18
    });
19
 
20
    // Make it possible to travel up tree.
21
    self.parent = parent; // (Could this be done a better way in the future?)
22
 
23
    /**
24
     * Keep track of child fields. Should not be exposed directly,
25
     * create functions for using or finding the children.
26
     *
27
     * @private
28
     * @type {Array}
29
     */
30
    var children = [];
31
 
32
    // Prepare the old ready callback system
33
    var readyCallbacks = [];
34
    var passReadyCallbacks = true;
35
    parent.ready(function () {
36
      passReadyCallbacks = false;
37
    }); // (In the future we should use the event system for this, i.e. self.once('ready'))
38
 
39
    // Listen for widget changes
40
    self.on('changeWidget', function () {
41
      // Append all items to new widget
42
      for (var i = 0; i < children.length; i++) {
43
        self.widget.addItem(children[i], i);
44
      }
45
    });
46
 
47
    /**
48
     * Add all items to list without appending to DOM.
49
     *
50
     * @public
51
     */
52
    var init = function () {
53
      var i;
54
      if (parameters !== undefined && parameters.length) {
55
        for (i = 0; i < parameters.length; i++) {
56
          if (parameters[i] === null) {
57
            parameters[i] = undefined;
58
          }
59
          addItem(i);
60
        }
61
      }
62
      else {
63
        if (field.defaultNum === undefined) {
64
          // Use min or 1 if no default item number is set.
65
          field.defaultNum = (field.min !== undefined ? field.min : 1);
66
        }
67
        // Add default number of fields.
68
        for (i = 0; i < field.defaultNum; i++) {
69
          addItem(i);
70
        }
71
      }
72
    };
73
 
74
    /**
75
     * Make sure list is created when setting a parameter.
76
     *
77
     * @private
78
     * @param {number} index
79
     * @param {*} value
80
     */
81
    var setParameters = function (index, value) {
82
      if (parameters === undefined) {
83
        // Create new parameters for list
84
        parameters = [];
85
        setValue(field, parameters);
86
      }
87
      parameters[index] = value;
88
    };
89
 
90
    /**
91
     * Add item to list.
92
     *
93
     * @private
94
     * @param {Number} index
95
     * @param {*} [paramsOverride] Override params using this value.
96
     */
97
    var addItem = function (index, paramsOverride) {
98
      var childField = field.field;
99
      var widget = H5PEditor.getWidgetName(childField);
100
 
101
      if ((parameters === undefined || parameters[index] === undefined) && childField['default'] !== undefined) {
102
        // Use default value
103
        setParameters(index, childField['default']);
104
      }
105
      if (paramsOverride !== undefined) {
106
        // Use override params
107
        setParameters(index, paramsOverride);
108
      }
109
 
110
      var child = children[index] = new H5PEditor.widgets[widget](self, childField, parameters === undefined ? undefined : parameters[index], function (myChildField, value) {
111
        var i = findIndex(child);
112
        setParameters(i === undefined ? index : i, value);
113
      });
114
 
115
      return child;
116
    };
117
 
118
    /**
119
     * Finds the index for the given child.
120
     *
121
     * @private
122
     * @param {Object} child field instance
123
     * @returns {Number} index
124
     */
125
    var findIndex = function (child) {
126
      for (var i = 0; i < children.length; i++) {
127
        if (children[i] === child) {
128
          return i;
129
        }
130
      }
131
    };
132
 
133
    /**
134
     * Get the singular form of the items added in the list.
135
     *
136
     * @public
137
     * @returns {String} The entity type
138
     */
139
    self.getEntity = function () {
140
      return (field.entity === undefined ? 'item' : field.entity);
141
    };
142
 
143
    /**
144
     * Adds a new list item and child field at the end of the list
145
     *
146
     * @public
147
     * @param {*} [paramsOverride] Override params using this value.
148
     * @returns {Boolean}
149
     */
150
    self.addItem = function (paramsOverride) {
151
      var id = children.length;
152
      if (field.max === id) {
153
        return false;
154
      }
155
 
156
      var child = addItem(id, paramsOverride);
157
      self.widget.addItem(child, id);
158
 
159
      if (!passReadyCallbacks) {
160
        // Run collected ready callbacks
161
        for (var i = 0; i < readyCallbacks.length; i++) {
162
          readyCallbacks[i]();
163
        }
164
        readyCallbacks = []; // Reset
165
      }
166
      self.trigger('addedItem', child);
167
 
168
      return true;
169
    };
170
 
171
    /**
172
     * Removes the list item at the given index.
173
     *
174
     * @public
175
     * @param {Number} index
176
     */
177
    self.removeItem = function (index) {
178
      // Remove child field
179
      children[index].remove();
180
      children.splice(index, 1);
181
 
182
      if (parameters !== undefined) {
183
        // Clean up parameters
184
        parameters.splice(index, 1);
185
        if (!parameters.length) {
186
          // Create new parameters for list
187
          parameters = undefined;
188
          setValue(field);
189
        }
190
      }
191
      self.trigger('removedItem', index);
192
    };
193
 
194
    /**
195
     * Removes all items.
196
     * This is useful if a widget wants to reset the list.
197
     *
198
     * @public
199
     */
200
    self.removeAllItems = function () {
201
      if (parameters === undefined) {
202
        return;
203
      }
204
 
205
      // Remove child fields
206
      for (var i = 0; i < children.length; i++) {
207
        children[i].remove();
208
      }
209
      children = [];
210
 
211
      // Clean up parameters
212
      parameters = undefined;
213
      setValue(field);
214
    };
215
 
216
    /**
217
     * Change the order of the items in the list.
218
     * Be aware that this may change the index of other existing items.
219
     *
220
     * @public
221
     * @param {Number} currentIndex
222
     * @param {Number} newIndex
223
     */
224
    self.moveItem = function (currentIndex, newIndex) {
225
      // Update child fields
226
      var child = children.splice(currentIndex, 1);
227
      children.splice(newIndex, 0, child[0]);
228
 
229
      // Update parameters
230
      if (parameters) {
231
        var params = parameters.splice(currentIndex, 1);
232
        parameters.splice(newIndex, 0, params[0]);
233
      }
234
    };
235
 
236
    /**
237
     * Allows ancestors and widgets to do stuff with our children.
238
     *
239
     * @public
240
     * @param {Function} task
241
     */
242
    self.forEachChild = function (task) {
243
      for (var i = 0; i < children.length; i++) {
244
        task(children[i], i);
245
      }
246
    };
247
 
248
    /**
249
     * Collect callback to run when the editor is ready. If this item isn't
250
     * ready yet, jusy pass them on to the parent item.
251
     *
252
     * @public
253
     * @param {Function} ready
254
     */
255
    self.ready = function (ready) {
256
      if (passReadyCallbacks) {
257
        parent.ready(ready);
258
      }
259
      else {
260
        readyCallbacks.push(ready);
261
      }
262
    };
263
 
264
    /**
265
     * Make sure that this field and all child fields are valid.
266
     *
267
     * @public
268
     * @returns {Boolean}
269
     */
270
    self.validate = function () {
271
      var self = this;
272
      var valid = true;
273
 
274
      // Remove old error messages
275
      self.clearErrors();
276
 
277
      // Make sure child fields are valid
278
      for (var i = 0; i < children.length; i++) {
279
        if (children[i].validate() === false) {
280
          valid = false;
281
        }
282
      }
283
 
284
      // Validate our self
285
      if (field.max !== undefined && field.max > 0 &&
286
          children !== undefined && children.length > field.max) {
287
        // Invalid, more parameters than max allowed.
288
        valid = false;
289
        self.setError(H5PEditor.t('core', 'listExceedsMax', {':max': field.max}));
290
      }
291
      if (field.min !== undefined && field.min > 0 &&
292
          (children === undefined || children.length < field.min)) {
293
        // Invalid, less parameters than min allowed.
294
        valid = false;
295
        self.setError(H5PEditor.t('core', 'listBelowMin', {':min': field.min}));
296
      }
297
 
298
      return valid;
299
    };
300
 
301
    self.getImportance = function () {
302
      if (field.importance !== undefined) {
303
        return H5PEditor.createImportance(field.importance);
304
      }
305
      else if (field.field.importance !== undefined) {
306
        return H5PEditor.createImportance(field.field.importance);
307
      }
308
      else {
309
        return '';
310
      }
311
    };
312
 
313
    /**
314
     * Creates a copy of the current valid value. A copy is created to avoid
315
     * mistakes like directly editing the parameter values, which will cause
316
     * inconsistencies between the parameters and the editor widgets.
317
     *
318
     * @public
319
     * @returns {Array}
320
     */
321
    self.getValue = function () {
322
      return (parameters === undefined ? parameters : $.extend(true, [], parameters));
323
    };
324
 
325
    /**
326
     * Get a copy of the field semantics used by this list to create rows.
327
     * @return {Object}
328
     */
329
    self.getField = function () {
330
      return $.extend(true, {}, field.field);
331
    };
332
 
333
    // Start the party!
334
    init();
335
  }
336
 
337
  // Extends the semantics structure
338
  List.prototype = Object.create(H5PEditor.SemanticStructure.prototype);
339
  List.prototype.constructor = List;
340
 
341
  return List;
342
})(H5P.jQuery);
343
 
344
// Register widget
345
H5PEditor.widgets.list = H5PEditor.List;