Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
H5PEditor.SemanticStructure = (function ($) {
2
 
3
  /**
4
   * The base of the semantic structure system.
5
   * All semantic structure class types will inherit this class.
6
   *
7
   * @class
8
   * @param {Object} field
9
   * @param {Object} defaultWidget
10
   */
11
  function SemanticStructure(field, defaultWidget) {
12
    var self = this;
13
 
14
    // Initialize event inheritance
15
    H5P.EventDispatcher.call(self);
16
 
17
    /**
18
     * Determine this fields label. Used in error messages.
19
     * @public
20
     */
21
    self.label = (field.label === undefined ? field.name : field.label);
22
 
23
    // Support old editor libraries
24
    self.field = {};
25
 
26
    const id = H5PEditor.getNextFieldId(field);
27
    const descriptionId = (field.description !== undefined ? H5PEditor.getDescriptionId(id) : undefined)
28
 
29
    /**
30
     * Global instance variables.
31
     * @private
32
     */
33
    var $widgetSelect, $wrapper, $inner, $errors, $helpText, widgets;
34
 
35
    /**
36
     * Initialize. Wrapped to avoid leaking variables
37
     * @private
38
     */
39
    var init = function () {
40
      // Create field wrapper
41
      $wrapper = $('<div/>', {
42
        'class': 'field ' + field.type + ' ' + H5PEditor.createImportance(field.importance)
43
      });
44
 
45
      /* We want to be in control of the label, description and errors
46
      containers to give the editor some structure. Also we do not provide
47
      direct access to the field object to avoid cluttering semantics.json with
48
      non-semantic properties and options. Getters and setters will be
49
      created for what is needed. */
50
 
51
      // Create field label
52
      if (field.label !== 0) {
53
        // Add label
54
        createLabel(self.label, field.optional, id).appendTo($wrapper);
55
      }
56
 
57
      // Create description
58
      var $description;
59
      if (field.description !== undefined) {
60
        $description = $('<div/>', {
61
          'id': descriptionId,
62
          'class': 'h5peditor-field-description',
63
          text: field.description,
64
          appendTo: $wrapper
65
        });
66
        $description.html($description.html().replace('\n', '<br/>'));
67
      }
68
 
69
      widgets = getValidWidgets();
70
      if (widgets.length > 1) {
71
        // Create widget select box
72
        $widgetSelect = $('<ul/>', {
73
          'class': 'h5peditor-widget-select',
74
          title: H5PEditor.t('core', 'editMode'),
75
          appendTo: $wrapper
76
        });
77
        for (var i = 0; i < widgets.length; i++) {
78
          addWidgetOption(widgets[i], i === 0);
79
        }
80
 
81
        // Allow custom styling when selector is present
82
        $wrapper.addClass('h5peditor-widgets');
83
      }
84
 
85
      // Create inner wrapper
86
      $inner = $('<div/>', {
87
        'class': 'h5peditor-widget-wrapper' + (widgets.length > 1 ? ' content' : ' '),
88
        appendTo: $wrapper
89
      });
90
 
91
      // Create errors container
92
      $errors = $('<div/>', {
93
        'class': 'h5p-errors'
94
      });
95
 
96
      // Create help text
97
      $helpText = $('<div/>', {
98
        'class': 'h5p-help-text'
99
      });
100
    };
101
 
102
    /**
103
     * Add widget select option.
104
     *
105
     * @private
106
     */
107
    var addWidgetOption = function (widget, active) {
108
      var $option = $('<li/>', {
109
        'class': 'h5peditor-widget-option' + (active ? ' ' + CLASS_WIDGET_ACTIVE : ''),
110
        text: widget.label,
111
        role: 'button',
112
        tabIndex: 1,
113
        on: {
114
          click: function () {
115
            // Update UI
116
            $widgetSelect.children('.' + CLASS_WIDGET_ACTIVE).removeClass(CLASS_WIDGET_ACTIVE);
117
            $option.addClass(CLASS_WIDGET_ACTIVE);
118
 
119
            // Change Widget
120
            changeWidget(widget.name);
121
          }
122
        }
123
      }).appendTo($widgetSelect);
124
    };
125
 
126
    /**
127
     * Get a list of widgets that are valid and loaded.
128
     *
129
     * @private
130
     * @throws {TypeError} widgets must be an array
131
     * @returns {Array} List of valid widgets
132
     */
133
    var getValidWidgets = function () {
134
      if (field.widgets === undefined) {
135
        // No widgets specified use default
136
        return [defaultWidget];
137
      }
138
      if (!(field.widgets instanceof Array)) {
139
        throw TypeError('widgets must be an array');
140
      }
141
 
142
      // Check if specified widgets are valid
143
      var validWidgets = [];
144
      for (var i = 0; i < field.widgets.length; i++) {
145
        var widget = field.widgets[i];
146
        if (getWidget(widget.name)) {
147
          validWidgets.push(widget);
148
        }
149
      }
150
 
151
      if (!validWidgets.length) {
152
        // There are no valid widgets, add default
153
        validWidgets.push(self.default);
154
      }
155
 
156
      return validWidgets;
157
    };
158
 
159
    /**
160
     * Finds the widget class with the given name.
161
     *
162
     * @private
163
     * @param {String} name
164
     * @returns {Class}
165
     */
166
    var getWidget = function (name) {
167
      return H5PEditor[name];
168
    };
169
 
170
    /**
171
     * Change the UI widget.
172
     *
173
     * @private
174
     * @param {String} name
175
     */
176
    var changeWidget = function (name) {
177
      if (self.widget !== undefined) {
178
        // Validate our fields first to makes sure all "stored" from their widgets
179
        self.validate();
180
 
181
        // Remove old widgets
182
        self.widget.remove();
183
      }
184
 
185
      // TODO: Improve error handling?
186
      var widget = getWidget(name);
187
      self.widget = new widget(self);
188
      self.trigger('changeWidget');
189
      self.widget.appendTo($inner);
190
 
191
      // Add errors container and description.
192
      $errors.appendTo($inner);
193
 
194
      if (self.widget.helpText !== undefined) {
195
        $helpText.html(self.widget.helpText).appendTo($inner);
196
      }
197
      else {
198
        $helpText.detach();
199
      }
200
    };
201
 
202
    /**
203
     * Appends the field widget to the given container.
204
     *
205
     * @public
206
     * @param {jQuery} $container
207
     */
208
    self.appendTo = function ($container) {
209
      // Use first widget by default
210
      changeWidget(widgets[0].name);
211
 
212
      $wrapper.appendTo($container);
213
    };
214
 
215
    /**
216
     * Remove this field and widget.
217
     *
218
     * @public
219
     */
220
    self.remove = function () {
221
      self.widget.remove();
222
      $wrapper.remove();
223
    };
224
 
225
    /**
226
     * Remove this field and widget.
227
     *
228
     * @public
229
     * @param {String} message
230
     */
231
    self.setError = function (message) {
232
      $errors.append(H5PEditor.createError(message));
233
    };
234
 
235
    /**
236
     * Clear error messages.
237
     *
238
     * @public
239
     */
240
    self.clearErrors = function () {
241
      $errors.html('');
242
    };
243
 
244
    /**
245
     * Get the name of this field.
246
     *
247
     * @public
248
     * @returns {String} Name of the current field
249
     */
250
    self.getName = function () {
251
      return field.name;
252
    };
253
 
254
    /**
255
     * Get the input id the label points to.
256
     *
257
     * @returns {String} Name of the current field
258
     */
259
    self.getId = function () {
260
      return id;
261
    };
262
 
263
    /**
264
     * Get the description id to point to.
265
     *
266
     * @returns {String} Name of the current field
267
     */
268
    self.getDescriptionId = function () {
269
      return descriptionId;
270
    };
271
 
272
    // Must be last
273
    init();
274
  }
275
 
276
  // Extends the event dispatcher
277
  SemanticStructure.prototype = Object.create(H5P.EventDispatcher.prototype);
278
  SemanticStructure.prototype.constructor = SemanticStructure;
279
 
280
  /**
281
   * Create generic editor label.
282
   *
283
   * @private
284
   * @param {String} text
285
   * @returns {jQuery}
286
   */
287
  var createLabel = function (text, optional, id) {
288
    return $('<label/>', {
289
      'for': id,
290
      'class': 'h5peditor-label' + (optional ? '' : ' h5peditor-required'),
291
      text: text
292
    });
293
  };
294
 
295
 
296
 
297
  /**
298
   * @constant
299
   */
300
  var CLASS_WIDGET_ACTIVE = 'h5peditor-widget-active';
301
 
302
  return SemanticStructure;
303
})(H5P.jQuery);