Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/* global ns */
2
H5PEditor.ListEditor = (function ($) {
3
 
4
  /**
5
   * Draws the list.
6
   *
7
   * @class
8
   * @param {List} list
9
   */
10
  function ListEditor(list) {
11
    var self = this;
12
 
13
    var entity = list.getEntity();
14
    // Create list html
15
    var $list = $('<ul/>', {
16
      id: list.getId(),
17
      'aria-describedby': list.getDescriptionId(),
18
      'class': 'h5p-ul'
19
    });
20
 
21
    // Create add button
22
    var $button = ns.createButton(list.getImportance(), H5PEditor.t('core', 'addEntity', {':entity': entity}), function () {
23
      list.addItem();
24
    }, true);
25
 
26
    // Used when dragging items around
27
    var adjustX, adjustY, marginTop, formOffset;
28
 
29
    /**
30
     * @private
31
     * @param {jQuery} $item
32
     * @param {jQuery} $placeholder
33
     * @param {Number} x
34
     * @param {Number} y
35
     */
36
    var moveItem = function ($item, $placeholder, x, y) {
37
      var currentIndex;
38
 
39
      // Adjust so the mouse is placed on top of the icon.
40
      x = x - adjustX;
41
      y = y - adjustY;
42
      $item.css({
43
        top: y - marginTop - formOffset.top,
44
        left: x - formOffset.left
45
      });
46
 
47
      // Try to move up.
48
      var $prev = $item.prev().prev();
49
      if ($prev.length && y < $prev.offset().top + ($prev.height() / 2)) {
50
        $prev.insertAfter($item);
51
 
52
        currentIndex = $item.index();
53
        list.moveItem(currentIndex, currentIndex - 1);
54
 
55
        return;
56
      }
57
 
58
      // Try to move down.
59
      var $next = $item.next();
60
      if ($next.length && y + $item.height() > $next.offset().top + ($next.height() / 2)) {
61
        $next.insertBefore($placeholder);
62
 
63
        currentIndex = $item.index() - 2;
64
        list.moveItem(currentIndex, currentIndex + 1);
65
      }
66
    };
67
 
68
    /**
69
     * Default confirm handler.
70
     *
71
     * @param {Object} item Content parameters
72
     * @param {number} id Index of element being removed
73
     * @param {Object} buttonOffset Delete button offset, useful for positioning dialog
74
     * @param {function} confirm Run to confirm delete
75
     */
76
    self.defaultConfirmHandler = function (item, id, buttonOffset, confirm) {
77
      // Create default confirmation dialog for removing list item
78
      const confirmRemovalDialog = new H5P.ConfirmationDialog({
79
        dialogText: H5PEditor.t('core', 'confirmRemoval', {':type': entity})
80
      }).appendTo(document.body);
81
 
82
      // Remove list item on confirmation
83
      confirmRemovalDialog.on('confirmed', confirm);
84
      confirmRemovalDialog.show(buttonOffset.top);
85
    };
86
 
87
    // Use the default confirmation handler by default
88
    let confirmHandler = self.defaultConfirmHandler;
89
 
90
    /**
91
     * Set a custom confirmation handler callback (instead of the default dialog)
92
     *
93
     * @public
94
     * @param {function} confirmHandler
95
     */
96
    self.setConfirmHandler = function (handler) {
97
      confirmHandler = handler;
98
    };
99
 
100
    /**
101
     * Adds UI items to the widget.
102
     *
103
     * @public
104
     * @param {Object} item
105
     */
106
    self.addItem = function (item) {
107
      var $placeholder, mouseDownAt;
108
      var $item = $('<li/>', {
109
        'class' : 'h5p-li',
110
      });
111
 
112
      /**
113
       * Mouse move callback
114
       *
115
       * @private
116
       * @param {Object} event
117
       */
118
      var move = function (event) {
119
        if (mouseDownAt) {
120
          // Have not started moving yet
121
 
122
          if (! (event.pageX > mouseDownAt.x + 5 || event.pageX < mouseDownAt.x - 5 ||
123
                 event.pageY > mouseDownAt.y + 5 || event.pageY < mouseDownAt.y - 5) ) {
124
            return; // Not ready to start moving
125
          }
126
 
127
          // Prevent wysiwyg becoming unresponsive
128
          H5PEditor.Html.removeWysiwyg();
129
 
130
          // Prepare to start moving
131
          mouseDownAt = null;
132
 
133
          var offset = $item.offset();
134
          adjustX = event.pageX - offset.left;
135
          adjustY = event.pageY - offset.top;
136
          marginTop = parseInt($item.css('marginTop'));
137
          formOffset = $list.offsetParent().offset();
138
          // TODO: Couldn't formOffset and margin be added?
139
 
140
          var width = $item.width();
141
          var height = $item.height();
142
 
143
          $item.addClass('moving').css({
144
            width: width,
145
            height: height
146
          });
147
          $placeholder = $('<li/>', {
148
            'class': 'placeholder h5p-li',
149
            css: {
150
              width: width,
151
              height: height
152
            }
153
          }).insertBefore($item);
154
        }
155
 
156
        moveItem($item, $placeholder, event.pageX, event.pageY);
157
      };
158
 
159
      /**
160
       * Mouse button release callback
161
       *
162
       * @private
163
       */
164
      var up = function () {
165
 
166
        // Stop listening for mouse move events
167
        H5P.$window
168
          .unbind('mousemove', move)
169
          .unbind('mouseup', up);
170
 
171
        // Enable text select again
172
        H5P.$body
173
          .css({
174
            '-moz-user-select': '',
175
            '-webkit-user-select': '',
176
            'user-select': '',
177
            '-ms-user-select': ''
178
          })
179
          .attr('unselectable', 'off')[0].onselectstart = H5P.$body[0].ondragstart = null;
180
 
181
        if (!mouseDownAt) {
182
          // Not your regular click, we have been moving
183
          $item.removeClass('moving').css({
184
            width: 'auto',
185
            height: 'auto'
186
          });
187
          $placeholder.remove();
188
 
189
          if (item instanceof H5PEditor.Group) {
190
            // Avoid groups expand/collapse toggling
191
            item.preventToggle = true;
192
          }
193
        }
194
      };
195
 
196
      /**
197
       * Mouse button down callback
198
       *
199
       * @private
200
       */
201
      var down = function (event) {
202
        if (event.which !== 1) {
203
          return; // Only allow left mouse button
204
        }
205
 
206
        mouseDownAt = {
207
          x: event.pageX,
208
          y: event.pageY
209
        };
210
 
211
        // Start listening for mouse move events
212
        H5P.$window
213
          .mousemove(move)
214
          .mouseup(up);
215
 
216
        // Prevent text select
217
        H5P.$body
218
          .css({
219
            '-moz-user-select': 'none',
220
            '-webkit-user-select': 'none',
221
            'user-select': 'none',
222
            '-ms-user-select': 'none'
223
          })
224
          .attr('unselectable', 'on')[0].onselectstart = H5P.$body[0].ondragstart = function () {
225
            return false;
226
          };
227
      };
228
 
229
      /**
230
       * Order current list item up
231
       *
232
       * @private
233
       */
234
      var moveItemUp = function () {
235
        var $prev = $item.prev();
236
        if (!$prev.length) {
237
          return; // Cannot move item further up
238
        }
239
 
240
        // Prevent wysiwyg becoming unresponsive
241
        H5PEditor.Html.removeWysiwyg();
242
 
243
        var currentIndex = $item.index();
244
        $prev.insertAfter($item);
245
        list.moveItem(currentIndex, currentIndex - 1);
246
      };
247
 
248
      /**
249
       * Order current ist item down
250
       *
251
       * @private
252
       */
253
      var moveItemDown = function () {
254
        var $next = $item.next();
255
        if (!$next.length) {
256
          return; // Cannot move item further down
257
        }
258
 
259
        // Prevent wysiwyg becoming unresponsive
260
        H5PEditor.Html.removeWysiwyg();
261
 
262
        var currentIndex = $item.index();
263
        $next.insertBefore($item);
264
        list.moveItem(currentIndex, currentIndex + 1);
265
      };
266
 
267
      // List item title bar
268
      var $titleBar = $('<div/>', {
269
        'class': 'list-item-title-bar',
270
        appendTo: $item
271
      });
272
 
273
      // Container for list actions
274
      var $listActions = $('<div/>', {
275
        class: 'list-actions',
276
        appendTo: $titleBar
277
      });
278
 
279
      // Append order button
280
      var $orderGroup = $('<div/>', {
281
        class : 'order-group',
282
        appendTo: $listActions
283
      });
284
 
285
      H5PEditor.createButton('order-up', H5PEditor.t('core', 'orderItemUp'), moveItemUp).appendTo($orderGroup);
286
      H5PEditor.createButton('order-down', H5PEditor.t('core', 'orderItemDown'), moveItemDown).appendTo($orderGroup);
287
 
288
      H5PEditor.createButton('remove', H5PEditor.t('core', 'removeItem'), function () {
289
        confirmHandler(item, $item.index(), $(this).offset(), function () {
290
          list.removeItem($item.index());
291
          $item.remove();
292
        });
293
      }).appendTo($listActions);
294
 
295
      // Append new field item to content wrapper
296
      if (item instanceof H5PEditor.Group) {
297
        // Append to item
298
        item.appendTo($item);
299
        $item.addClass('listgroup');
300
        $titleBar.addClass(list.getImportance());
301
 
302
        // Move label
303
        $item.children('.field').children('.title').appendTo($titleBar).addClass('h5peditor-label');
304
 
305
        // Handle expand and collapse
306
        item.on('expanded', function () {
307
          $item.addClass('expanded').removeClass('collapsed');
308
        });
309
        item.on('collapsed', function () {
310
          $item.removeClass('expanded').addClass('collapsed');
311
        });
312
      }
313
      else {
314
        // Append content wrapper
315
        var $content = $('<div/>', {
316
          'class' : 'content'
317
        }).appendTo($item);
318
 
319
        // Add importance to items not in groups
320
        $titleBar.addClass(list.getImportance());
321
 
322
        // Append field
323
        item.appendTo($content);
324
 
325
        if (item.field.label !== 0) {
326
          // Try to find and move the label to the title bar
327
          const $label = $content.children('.field').find('.h5peditor-label:first');
328
 
329
          if ($label.length !== 0) {
330
            $titleBar.append($('<label/>', {
331
              'class': 'h5peditor-label',
332
              'for': $label.parent().attr('for'),
333
              html: $label.html()
334
            }));
335
 
336
            $label.hide();
337
          }
338
        }
339
      }
340
 
341
      // Append item to list
342
      $item.appendTo($list);
343
 
344
      if (item instanceof H5PEditor.Group && item.field.expanded !== false) {
345
        // Good UX: automatically expand groups if not explicitly disabled by semantics
346
        item.expand();
347
      }
348
 
349
      $titleBar.children('.h5peditor-label').mousedown(down);
350
    };
351
 
352
    /**
353
     * Determine if child is a text field
354
     *
355
     * @param {Object} child
356
     * @returns {boolean} True if child is a text field
357
     */
358
    self.isTextField = function (child) {
359
      var widget = ns.getWidgetName(child.field);
360
      return widget === 'html' || widget === 'text';
361
    };
362
 
363
    /**
364
     * Puts this widget at the end of the given container.
365
     *
366
     * @public
367
     * @param {jQuery} $container
368
     */
369
    self.appendTo = function ($container) {
370
      $list.appendTo($container);
371
      $button.appendTo($container);
372
    };
373
 
374
    /**
375
     * Remove this widget from the editor DOM.
376
     *
377
     * @public
378
     */
379
    self.remove = function () {
380
      $list.remove();
381
      $button.remove();
382
    };
383
  }
384
 
385
  return ListEditor;
386
})(H5P.jQuery);