Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
document.addEventListener("DOMContentLoaded", function() {
2
  var container = document.getElementById("gradable-container");
3
  var questions = [];
4
  var questionElements = container.querySelectorAll('.h5p-iv-open-ended-reporting-container');
5
  var inputs = [];
6
  var maxScores = {};
7
  var index = 0;
8
  var currentQuestion = questionElements[0];
9
 
10
  // Translatable labels
11
  var IVOpenEndedQuestionTitle;
12
  var scoreLabel;
13
  var scoreDelimiter;
14
  var questionsRemainingLabel;
15
  var submitButtonLabel;
16
 
17
  // Render each of the question containers
18
  for (var i = 0; i < questionElements.length; i++) {
19
    IVOpenEndedQuestionTitle = questionElements[i].getAttribute('data-report-iv-open-ended-question-title');
20
    scoreLabel = questionElements[i].getAttribute('data-report-score-label');
21
    scoreDelimiter = questionElements[i].getAttribute('data-report-score-delimiter');
22
    questionsRemainingLabel = questionElements[i].getAttribute('data-report-questions-remaining-label');
23
    submitButtonLabel = questionElements[i].getAttribute('data-report-submit-button-label');
24
 
25
    // Add the title to an existing div in the the header
26
    addTitle(i);
27
 
28
    // Add other elements to the header
29
    var header = document.getElementById('h5p-iv-open-ended-reporting-header-' + i);
30
 
31
    var gradeInputWrapper = document.createElement('div');
32
    gradeInputWrapper.classList.add('h5p-iv-open-ended-reporting-grade-input-wrapper');
33
 
34
    var inputDiv = createInputDiv(questionElements[i], i);
35
    gradeInputWrapper.append(inputDiv);
36
 
37
    var submitButtonWrapper = createSubmitButtonWrapper(i);
38
    gradeInputWrapper.append(submitButtonWrapper);
39
 
40
    header.append(gradeInputWrapper);
41
 
42
    // Add the header to the question container
43
    questionElements[i].prepend(header);
44
 
45
    // Keep track of the elements created and general data for later use
46
    questions[i] = {};
47
    questions[i] = {
48
      'element': questionElements[i],
49
      'inputDiv': inputDiv,
50
      'submitButton': submitButtonWrapper,
51
      'gradebookContainer': questionElements[i].querySelectorAll('.h5p-iv-open-ended-reporting-scores')[0]
52
    };
53
  }
54
 
55
  updateMainGradeBookContainer();
56
 
57
  /**
58
   * Add a title
59
   *
60
   * @param {number} index
61
   * @return {null}
62
   */
63
  function addTitle(index) {
64
    var titleCounter = document.createElement('div');
65
    titleCounter.classList.add('h5p-iv-open-ended-title-counter');
66
    titleCounter.innerHTML = IVOpenEndedQuestionTitle + ' ' + '<span>' + (index + 1) + ' ' + scoreDelimiter + ' ' + questionElements.length + '</span>';
67
 
68
    var titleWrapper = document.getElementById('h5p-iv-open-ended-reporting-title-wrapper-' + index);
69
    titleWrapper.prepend(titleCounter);
70
  }
71
 
72
  /**
73
   * Create submit button wrapper
74
   * @param {number} index
75
   * @return {HTMLElement}
76
   */
77
  function createSubmitButtonWrapper(index) {
78
    var submitButtonWrapper = document.createElement('div');
79
    submitButtonWrapper.classList.add('h5p-iv-open-ended-reporting-submit-button-wrapper');
80
 
81
    var submitButton = document.createElement('button');
82
    submitButton.classList.add('h5p-iv-open-ended-reporting-submit-button');
83
    submitButton.id = 'h5p-iv-open-ended-reporting-submit-button-' + index;
84
    submitButton.innerHTML = submitButtonLabel;
85
 
86
    submitButtonWrapper.append(submitButton);
87
    return submitButtonWrapper;
88
  }
89
 
90
  /**
91
   * Create input wrapper
92
   * @param {HTMLElement} wrapper
93
   * @param {number} index
94
   * @return {HTMLElement}
95
   */
96
  function createInputDiv(wrapper, index) {
97
    var inputDiv = document.createElement('div');
98
    inputDiv.classList.add('h5p-iv-open-ended-input-div');
99
 
100
    var scoreText = document.createElement('span');
101
    scoreText.innerHTML = scoreLabel + ': ';
102
    inputDiv.append(scoreText);
103
 
104
    var input = document.createElement('input');
105
    input.setAttribute('type', 'number');
106
    input.id = 'h5p-grade-input-' + index;
107
    input.subcontentID = wrapper.getAttribute('data-report-id');
108
    input.scaleFactor = wrapper.getAttribute('data-report-scale');
109
    input.maxScore = wrapper.getAttribute('data-report-max');
110
    inputDiv.append(input);
111
 
112
    var maxScoreText = document.createElement('span');
113
    maxScoreText.id = 'h5p-max-score-text-' + index;
114
    inputDiv.append(maxScoreText);
115
 
116
    inputs.push(input);
117
    return inputDiv;
118
  }
119
 
120
  // Add logic to the inputs
121
  inputs.forEach(function(input, index) {
122
    // Populate the inputs with existing questionElements
123
    populateInputDiv(input.subcontentID, index);
124
 
125
    input.addEventListener('focus', function() {
126
      var submitButton = document.getElementById('h5p-iv-open-ended-reporting-submit-button-' + index);
127
      submitButton.disabled = false;
128
    });
129
 
130
    // Validate on blur
131
    input.addEventListener('blur', function() {
132
      if (this.value == '' || parseInt(this.value) < 0) {
133
        this.value = 0;
134
      }
135
 
136
      if (parseInt(this.value) > parseInt(maxScores[index])) {
137
        this.value = maxScores[index];
138
      }
139
    });
140
 
141
    // Add logic for the corresponding submit button
142
    var submitButton = document.getElementById('h5p-iv-open-ended-reporting-submit-button-' + index);
143
    submitButton.addEventListener('click', function() {
144
 
145
      // Validate on submit again since blur doesn't always work
146
      if (this.value == '' || parseInt(this.value) < 0) {
147
        this.value = 0;
148
      }
149
 
150
      if (parseInt(this.value) > parseInt(maxScores[index])) {
151
        this.value = maxScores[index];
152
      }
153
 
154
      H5P.jQuery.post(data_for_page.setSubContentEndpoint, {
155
        subcontent_id: input.subcontentID,
156
        score: input.value,
157
        maxScore: input.maxScore
158
      }, function(response) {
159
        renderAfterSubmit(input, index, response.data.totalUngraded)
160
      });
161
    });
162
  });
163
 
164
  /**
165
   * rerenders elements with new data
166
   * @param {HTMLElement} input
167
   * @param {number} index
168
   * @param {number} totalUngraded
169
   */
170
  function renderAfterSubmit(input, index, totalUngraded) {
171
    hideInputs(index);
172
 
173
    // Update the gradebook score for this question and for the main content type
174
    updateGradeBookContainer(index, input.value, input.scaleFactor);
175
    updateMainGradeBookContainer();
176
    updateQuestionCounter(totalUngraded);
177
  }
178
 
179
  /**
180
   * hide inputs
181
   *
182
   * @param {number} index
183
   */
184
  function hideInputs(index) {
185
    questions[index].submitButton.classList.add('h5p-iv-open-ended-reporting-hidden');
186
    questions[index].inputDiv.classList.add('h5p-iv-open-ended-reporting-hidden');
187
  }
188
 
189
 
190
  /**
191
   * Updates the gradebook scores for a particular question
192
   *
193
   * @param {number} index
194
   * @param {number} inputValue
195
   * @param  {float} scaleFactor
196
   */
197
  function updateGradeBookContainer(index, inputValue, scaleFactor) {
198
    var scoreContainer = document.getElementById('h5p-iv-open-ended-reporting-score-' + index);
199
    scoreContainer.classList.remove('h5p-iv-open-ended-reporting-hidden');
200
 
201
    var scaledScoreElement = scoreContainer.querySelectorAll('.h5p-reporting-scaled-score')[0];
202
    scaledScoreElement.innerHTML = Math.round((scaleFactor * inputValue) * 100 + Number.EPSILON) / 100;
203
 
204
    var rawScoreElement = scoreContainer.querySelectorAll('.h5p-reporting-raw-score')[0];
205
    rawScoreElement.innerHTML = inputValue;
206
  }
207
 
208
 
209
  /**
210
   * Updates the values of the main gradebook container for the containing content type
211
   */
212
  function updateMainGradeBookContainer() {
213
    // Only look within the same report
214
    var thisReport = findAncestor(container, '.h5p-reporting-main-container');
215
    var thisReportView = findAncestor(container, '.h5p-report-view');
216
    var rawScores = thisReport.querySelectorAll('.h5p-reporting-raw-score');
217
    rawScores = Array.prototype.slice.call(rawScores).map(function(rawScoreElement) {
218
      return parseInt(rawScoreElement.innerHTML);
219
    });
220
    var rawScore = rawScores.reduce(function(a,b) {
221
      return a + b;
222
    });
223
    var mainRawScoreElement = thisReport.querySelectorAll('.h5p-reporting-main-score-raw-score')[0];
224
    mainRawScoreElement.innerHTML = rawScore;
225
 
226
    // Update the gradebook score
227
    var scaledScores = thisReportView.querySelectorAll('.h5p-reporting-scaled-score');
228
    scaledScores = Array.prototype.slice.call(scaledScores).map(function(scaledScoreElement) {
229
      return parseFloat(scaledScoreElement.innerHTML);
230
    });
231
 
232
    var scaledScore = scaledScores.reduce(function(a,b) {
233
      return a + b;
234
    });
235
 
236
    var scaledScoreElement = thisReport.querySelectorAll('.h5p-reporting-main-score-scaled-score')[0];
237
    scaledScoreElement.innerHTML = Number((scaledScore).toFixed(2));
238
  }
239
 
240
 
241
  /**
242
   * Renders the input div
243
   *
244
   * @param {number} subcontentID
245
   * @param {number} index
246
   */
247
  function populateInputDiv(subcontentID, index) {
248
    H5P.jQuery.get(data_for_page.getSubContentEndpoint, {subcontent_id : subcontentID}, function(response) {
249
      var loadedInput = document.getElementById('h5p-grade-input-' + index);
250
      loadedInput.value = response.data.score;
251
 
252
      var loadedMaxScore = document.getElementById('h5p-max-score-text-' + index);
253
      loadedMaxScore.innerHTML = scoreDelimiter + ' ' + response.data.maxScore;
254
      maxScores[index] = response.data.maxScore;
255
 
256
      // Disable buttons if the content type hasn't been graded yet
257
      if (response.data.score === null) {
258
        var submitButton = document.getElementById('h5p-iv-open-ended-reporting-submit-button-' + index);
259
        submitButton.disabled = true;
260
      }
261
      else {
262
        // Hide input div and show grade container if it already has been graded
263
        hideInputs(index);
264
        updateGradeBookContainer(index, loadedInput.value, loadedInput.scaleFactor);
265
      }
266
 
267
      updateQuestionCounter(response.data.totalUngraded);
268
    });
269
  }
270
 
271
 
272
  /**
273
   * Updates the remanining question counter
274
   *
275
   * @param {number} totalUngraded
276
   */
277
  function updateQuestionCounter(totalUngraded) {
278
    if (totalUngraded > 0) {
279
      container.querySelectorAll('.h5p-iv-open-ended-reporting-question-counter').forEach(function(questionCounter) {
280
        questionCounter.innerHTML = '<span>' + totalUngraded + ' ' + questionsRemainingLabel + '</span>';
281
      });
282
    } else {
283
      container.querySelectorAll('.h5p-iv-open-ended-reporting-question-counter').forEach(function(questionCounter) {
284
        questionCounter.innerHTML = '<span>All questions have been graded</span>';
285
        questionCounter.classList.add('reporting-completed');
286
      });
287
    }
288
  }
289
 
290
  // Initialize buttons
291
  container.querySelectorAll('.h5p-iv-open-ended-previous').forEach(function(button, index) {
292
    button.addEventListener("click", showPreviousQuestion);
293
 
294
    // Disable the first previous button
295
    if (index === 0) {
296
      button.disabled = true;
297
    }
298
  });
299
 
300
  container.querySelectorAll('.h5p-iv-open-ended-next').forEach(function(button, index) {
301
    button.addEventListener("click", showNextQuestion);
302
 
303
    // Disable the last next button
304
    if (index === container.querySelectorAll('.h5p-iv-open-ended-next').length - 1) {
305
      button.disabled = true;
306
    }
307
  });
308
 
309
  // Add logic to the 'Change grade' button to show the input again
310
  container.querySelectorAll('.h5p-iv-open-ended-reporting-change-grade').forEach(function(button) {
311
    var index = button.getAttribute('data-report-id');
312
    button.addEventListener('click', function() {
313
      questions[index].inputDiv.classList.remove('h5p-iv-open-ended-reporting-hidden');
314
      questions[index].submitButton.classList.remove('h5p-iv-open-ended-reporting-hidden');
315
      questions[index].gradebookContainer.classList.add('h5p-iv-open-ended-reporting-hidden');
316
    });
317
  });
318
 
319
  /**
320
   * showPreviousQuestion
321
   */
322
  function showPreviousQuestion() {
323
    // If we are on the first question don't do anything
324
    if (index === 0) {
325
      return;
326
    }
327
    currentQuestion.classList.add('h5p-iv-open-ended-reporting-hidden');
328
 
329
    index -= 1;
330
    currentQuestion = questionElements[index];
331
    currentQuestion.classList.remove('h5p-iv-open-ended-reporting-hidden');
332
  }
333
 
334
  /**
335
   * showNextQuestion
336
   */
337
  function showNextQuestion() {
338
    if (index == questionElements.length - 1) {
339
      return;
340
    }
341
    currentQuestion.classList.add('h5p-iv-open-ended-reporting-hidden');
342
 
343
    index += 1;
344
    currentQuestion = questionElements[index];
345
    currentQuestion.classList.remove('h5p-iv-open-ended-reporting-hidden');
346
  }
347
 
348
  /**
349
   * Finds an ancestor that matches a selector
350
   *
351
   * @param  {type} el
352
   * @param  {type} sel
353
   * @return {HTMLElement} element to be returned
354
   */
355
  function findAncestor (el, sel) {
356
    while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
357
    return el;
358
  }
359
});