mumuki-laboratory 8.1.1 → 8.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -8
  3. data/app/assets/javascripts/mumuki_laboratory/application/bridge.js +2 -1
  4. data/app/assets/javascripts/mumuki_laboratory/application/button.js +4 -6
  5. data/app/assets/javascripts/mumuki_laboratory/application/codemirror-builder.js +3 -3
  6. data/app/assets/javascripts/mumuki_laboratory/application/codemirror.js +6 -6
  7. data/app/assets/javascripts/mumuki_laboratory/application/console.js +2 -2
  8. data/app/assets/javascripts/mumuki_laboratory/application/discussions.js +7 -7
  9. data/app/assets/javascripts/mumuki_laboratory/application/editors.js +1 -1
  10. data/app/assets/javascripts/mumuki_laboratory/application/elipsis.js +1 -1
  11. data/app/assets/javascripts/mumuki_laboratory/application/events.js +2 -2
  12. data/app/assets/javascripts/mumuki_laboratory/application/exercise.js +2 -2
  13. data/app/assets/javascripts/mumuki_laboratory/application/gamification.js +13 -3
  14. data/app/assets/javascripts/mumuki_laboratory/application/i18n.js +73 -0
  15. data/app/assets/javascripts/mumuki_laboratory/application/inputs.js +1 -1
  16. data/app/assets/javascripts/mumuki_laboratory/application/kids.js +26 -5
  17. data/app/assets/javascripts/mumuki_laboratory/application/kindergarten.js +13 -8
  18. data/app/assets/javascripts/mumuki_laboratory/application/messages.js +6 -6
  19. data/app/assets/javascripts/mumuki_laboratory/application/mu-modal-carrousel.js +1 -1
  20. data/app/assets/javascripts/mumuki_laboratory/application/multiple-choice.js +1 -1
  21. data/app/assets/javascripts/mumuki_laboratory/application/multiple-files.js +3 -3
  22. data/app/assets/javascripts/mumuki_laboratory/application/multiple-scenarios.js +1 -1
  23. data/app/assets/javascripts/mumuki_laboratory/application/pin.js +1 -1
  24. data/app/assets/javascripts/mumuki_laboratory/application/primary.js +6 -4
  25. data/app/assets/javascripts/mumuki_laboratory/application/progress.js +1 -1
  26. data/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js +29 -2
  27. data/app/assets/javascripts/mumuki_laboratory/application/speech-bubble-renderer.js +4 -4
  28. data/app/assets/javascripts/mumuki_laboratory/application/submission.js +72 -48
  29. data/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js +3 -3
  30. data/app/assets/javascripts/mumuki_laboratory/application/sync-mode.js +2 -2
  31. data/app/assets/javascripts/mumuki_laboratory/application/timer.js +1 -1
  32. data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +7 -7
  33. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kids.scss +4 -0
  34. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kids_results.scss +1 -0
  35. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_overlap.scss +0 -4
  36. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_terms.scss +4 -0
  37. data/app/controllers/chapters_controller.rb +9 -5
  38. data/app/controllers/concerns/with_user_discussion_validation.rb +6 -0
  39. data/app/controllers/discussions_controller.rb +0 -6
  40. data/app/controllers/guide_container_controller.rb +2 -7
  41. data/app/helpers/assignment_result_helper.rb +1 -1
  42. data/app/helpers/contextualization_result_helper.rb +0 -8
  43. data/app/helpers/discussions_helper.rb +12 -4
  44. data/app/helpers/editor_tabs_helper.rb +1 -1
  45. data/app/helpers/icons_helper.rb +1 -1
  46. data/app/helpers/links_helper.rb +3 -3
  47. data/app/helpers/menu_bar_helper.rb +9 -1
  48. data/app/helpers/overlapped_buttons_helper.rb +6 -2
  49. data/app/views/book/show.html.erb +2 -2
  50. data/app/views/book_discussions/index.html.erb +3 -1
  51. data/app/views/chapters/show.html.erb +21 -9
  52. data/app/views/complements/show.html.erb +1 -1
  53. data/app/views/discussions/_message.html.erb +2 -2
  54. data/app/views/discussions/index.html.erb +11 -4
  55. data/app/views/exams/show.html.erb +1 -1
  56. data/app/views/exercise_solutions/_kids_level_up.html.erb +1 -1
  57. data/app/views/exercises/_exercise_assignment.html.erb +1 -1
  58. data/app/views/exercises/_read_only.html.erb +1 -1
  59. data/app/views/exercises/show.html.erb +2 -2
  60. data/app/views/layouts/_copyright.html.erb +1 -1
  61. data/app/views/layouts/_discussions.html.erb +0 -4
  62. data/app/views/layouts/_guide.html.erb +9 -36
  63. data/app/views/layouts/_guide_container.html.erb +28 -0
  64. data/app/views/layouts/_guide_title_icons.html.erb +9 -0
  65. data/app/views/layouts/_kids.html.erb +4 -4
  66. data/app/views/layouts/_kindergarten.html.erb +5 -5
  67. data/app/views/layouts/_social_media.html.erb +4 -4
  68. data/app/views/layouts/_timer.html.erb +1 -1
  69. data/app/views/layouts/application.html.erb +31 -27
  70. data/app/views/layouts/embedded.html.erb +14 -11
  71. data/app/views/layouts/exercise_inputs/editors/_code.html.erb +1 -6
  72. data/app/views/layouts/exercise_inputs/editors/_multiple_files.html.erb +4 -9
  73. data/app/views/layouts/exercise_inputs/forms/_problem_form.html.erb +1 -1
  74. data/app/views/layouts/exercise_inputs/layouts/_input_kindergarten.html.erb +1 -1
  75. data/app/views/layouts/modals/_guide_corollary.html.erb +13 -3
  76. data/app/views/layouts/modals/_kids_results.html.erb +2 -2
  77. data/app/views/layouts/modals/_kindergarten_context.html.erb +3 -3
  78. data/app/views/layouts/modals/_kindergarten_results.html.erb +3 -3
  79. data/app/views/layouts/modals/_kindergarten_results_aborted.html.erb +2 -2
  80. data/app/views/layouts/modals/_level_up.html.erb +1 -1
  81. data/app/views/lessons/show.html.erb +1 -1
  82. data/app/views/users/_edit_user_form.html.erb +1 -1
  83. data/app/views/users/_term.html.erb +1 -1
  84. data/app/views/users/_user_form.html.erb +1 -1
  85. data/lib/mumuki/laboratory/controllers/results_rendering.rb +2 -1
  86. data/lib/mumuki/laboratory/engine.rb +1 -1
  87. data/lib/mumuki/laboratory/locales/en.yml +5 -8
  88. data/lib/mumuki/laboratory/locales/es-CL.yml +5 -3
  89. data/lib/mumuki/laboratory/locales/es.yml +8 -10
  90. data/lib/mumuki/laboratory/locales/pt.yml +5 -8
  91. data/lib/mumuki/laboratory/version.rb +1 -1
  92. data/spec/controllers/discussions_controller_spec.rb +19 -0
  93. data/spec/controllers/exercise_solutions_controller_spec.rb +3 -2
  94. data/spec/dummy/db/schema.rb +50 -1
  95. data/spec/dummy/public/character/animations.json +1 -0
  96. data/{public → spec/dummy/public}/character/kibi/context.svg +0 -0
  97. data/{public → spec/dummy/public}/character/kibi/failure.svg +0 -0
  98. data/{public → spec/dummy/public}/character/kibi/jump.svg +0 -0
  99. data/spec/dummy/public/character/kibi/passed_with_warnings.svg +4 -0
  100. data/{public → spec/dummy/public}/character/kibi/success2_l.svg +0 -0
  101. data/{public → spec/dummy/public}/character/kibi/success_l.svg +0 -0
  102. data/{public → spec/dummy/public}/character/magnifying_glass/apparition.svg +0 -0
  103. data/{public → spec/dummy/public}/character/magnifying_glass/loop.svg +0 -0
  104. data/spec/features/chapters_flow_spec.rb +112 -0
  105. data/spec/features/login_flow_spec.rb +1 -1
  106. data/spec/features/terms_flow_spec.rb +2 -0
  107. data/spec/features/topic_flow_spec.rb +0 -1
  108. data/spec/helpers/icons_helper_spec.rb +3 -3
  109. data/spec/helpers/test_results_rendering_spec.rb +8 -8
  110. data/spec/helpers/with_navigation_spec.rb +14 -14
  111. data/spec/javascripts/gamification-spec.js +2 -2
  112. data/spec/javascripts/i18n-spec.js +79 -0
  113. data/spec/javascripts/kids-button-spec.js +36 -0
  114. metadata +136 -115
  115. data/spec/dummy/config/database.travis.yml +0 -4
  116. data/spec/features/chapter_spec.rb +0 -70
@@ -13,7 +13,7 @@ mumuki.load(() => {
13
13
  this.$contextModalButton = new mumuki.Button($('#mu-kids-context .mu-kids-modal-button.mu-close'));
14
14
 
15
15
  this.resultActions.passed = this._showSuccessPopup.bind(this);
16
- this.resultActions.passed_with_warnings = this._showSuccessPopup.bind(this);
16
+ this.resultActions.passed_with_warnings = this._showPassedWithWarnings.bind(this);
17
17
  this.resultActions.failed = this._showFailurePopup.bind(this);
18
18
  this.resultActions.errored = this._showFailurePopup.bind(this);
19
19
  this.resultActions.pending = this._showFailurePopup.bind(this);
@@ -50,6 +50,10 @@ mumuki.load(() => {
50
50
  this.showNonAbortedPopup(data, 'success2_l');
51
51
  }
52
52
 
53
+ _showPassedWithWarnings(data) {
54
+ this.showNonAbortedPopup(data, 'passed_with_warnings');
55
+ }
56
+
53
57
  _showFailurePopup(data) {
54
58
  this.showNonAbortedPopup(data, 'failure');
55
59
  }
@@ -78,6 +82,7 @@ mumuki.load(() => {
78
82
 
79
83
  restart() {
80
84
  mumuki.presenterCharacter.playAnimation('talk', this.$bubbleCharacterAnimation);
85
+ this.hideOverlay();
81
86
  }
82
87
 
83
88
  // =======================
@@ -103,27 +108,27 @@ mumuki.load(() => {
103
108
  this._action('play', 'stop', true, (speech) => {
104
109
  mumuki.presenterCharacter.playAnimation('talk', mumuki.kids.$bubbleCharacterAnimation);
105
110
  speech.speak(msg);
106
- })
111
+ });
107
112
  },
108
113
  stop() {
109
- this._action('stop', 'play', false, (speech) => speech.cancel())
114
+ this._action('stop', 'play', false, (speech) => speech.cancel());
110
115
  },
111
116
  _action(add, remove, isPlaying, callback) {
112
117
  callback(window.speechSynthesis);
113
- const $button = $('.mu-kindergarten-play-description')
118
+ const $button = $('.mu-kindergarten-play-description');
114
119
  $button.find(`.mu-kindergarten-${add}`).addClass('hidden');
115
120
  $button.find(`.mu-kindergarten-${remove}`).removeClass('hidden');
116
121
  this._isPlaying = isPlaying;
117
122
  },
118
123
  verifyBrowserSupport() {
119
124
  if (!window.speechSynthesis) {
120
- const $button = $('.mu-kindergarten-play-description')
125
+ const $button = $('.mu-kindergarten-play-description');
121
126
  $button.prop('disabled', true);
122
127
  $button.css('cursor', 'not-allowed');
123
- this._action('play', 'stop', false)
128
+ this._action('play', 'stop', false);
124
129
  }
125
130
  }
126
- }
131
+ };
127
132
 
128
133
  }
129
134
 
@@ -143,7 +148,7 @@ mumuki.load(() => {
143
148
  const $hintMedia = $('.mu-kindergarten-hint-media');
144
149
  if (!$hintMedia.get(0)) $button.addClass('hidden');
145
150
  },
146
- }
151
+ };
147
152
  }
148
153
 
149
154
  get context() {
@@ -1,7 +1,7 @@
1
1
  mumuki.load(() => {
2
2
  var Chat = {
3
3
  $body: function () {
4
- return $('body')
4
+ return $('body');
5
5
  },
6
6
  $newMessageModal: function () {
7
7
  return $('.new-message-modal');
@@ -18,7 +18,7 @@ mumuki.load(() => {
18
18
  $('.notifications-box').toggleClass('notifications-box-empty', !data.has_messages);
19
19
  $('.pending-messages-filter').removeClass('pending-messages-filter');
20
20
  $('button.btn-submit').removeClass('disabled');
21
- $('.pending-messages-text').remove()
21
+ $('.pending-messages-text').remove();
22
22
  },
23
23
  readMessages: function (url) {
24
24
  Chat.tokenRequest({
@@ -26,10 +26,10 @@ mumuki.load(() => {
26
26
  method: 'POST',
27
27
  success: Chat.setMessages,
28
28
  xhrFields: {withCredentials: true}
29
- })
29
+ });
30
30
  },
31
31
  tokenRequest: function (data) {
32
- $.ajax(Chat.token.newRequest(data))
32
+ $.ajax(Chat.token.newRequest(data));
33
33
  },
34
34
  getMessages: function () {
35
35
  if ($('.badge-messages').length == 0) {
@@ -74,7 +74,7 @@ mumuki.load(() => {
74
74
  success: success,
75
75
  error: error,
76
76
  xhrFields: {withCredentials: true}
77
- })
77
+ });
78
78
  },
79
79
  openNewMessageModal: function () {
80
80
  Chat.$newMessageModal().modal({backdrop: false, keyboard: false});
@@ -89,5 +89,5 @@ mumuki.load(() => {
89
89
  Chat.setMessagesInterval();
90
90
  mumuki.Chat = Chat;
91
91
 
92
- })
92
+ });
93
93
 
@@ -41,7 +41,7 @@ mumuki.ModalCarrousel = (() => {
41
41
 
42
42
  _hidePreviousButtonIfFirstSlide() {
43
43
  const $prev = $('.mu-kids-modal-button.mu-previous');
44
- this._addClassIf($prev, 'hidden', () => this._activeSlide().is(':first-child'))
44
+ this._addClassIf($prev, 'hidden', () => this._activeSlide().is(':first-child'));
45
45
  }
46
46
 
47
47
  _showFirstSlide() {
@@ -1,7 +1,7 @@
1
1
  mumuki.load(() => {
2
2
  function dumpChoices(_evt) {
3
3
  var indexes = $('.solution-choice:checked').map(function () {
4
- return $(this).data('index')
4
+ return $(this).data('index');
5
5
  }).get().join(':');
6
6
  $('#solution_content').attr('value', indexes);
7
7
  }
@@ -103,11 +103,11 @@ mumuki.load(() => {
103
103
  }
104
104
 
105
105
  get highlightModes() {
106
- return this._getDataFromHiddenInput('#highlight-modes')
106
+ return this._getDataFromHiddenInput('#highlight-modes');
107
107
  }
108
108
 
109
109
  get locales() {
110
- return this._getDataFromHiddenInput('#multifile-locales')
110
+ return this._getDataFromHiddenInput('#multifile-locales');
111
111
  }
112
112
 
113
113
  setUpAddFile() {
@@ -131,7 +131,7 @@ mumuki.load(() => {
131
131
 
132
132
  this._setVisibility(this._addFileButton, filesCount < this.MAX_TABS);
133
133
  this.files.toArray().forEach(file => {
134
- this._setVisibility(file.deleteButton, file.name !== this.mainFile && filesCount > 1)
134
+ this._setVisibility(file.deleteButton, file.name !== this.mainFile && filesCount > 1);
135
135
  });
136
136
  }
137
137
 
@@ -73,7 +73,7 @@ mumuki.MultipleScenarios = (() => {
73
73
  if (this.validScenarioIndex(newScenarioIndex)) {
74
74
  this.setActiveIndex(newScenarioIndex);
75
75
  }
76
- })
76
+ });
77
77
  }
78
78
 
79
79
  createControls () {
@@ -11,5 +11,5 @@ mumuki.pin = (() => {
11
11
  smoothScrollToElement(scrollPin);
12
12
  }
13
13
  }
14
- }
14
+ };
15
15
  })();
@@ -16,7 +16,6 @@ mumuki.load(() => {
16
16
  super.initialize();
17
17
  this.$characterSpeechBubble = $('.mu-kids-character-speech-bubble');
18
18
  this.$characterSpeechBubbleNormal = this.$characterSpeechBubble.children('.mu-kids-character-speech-bubble-normal');
19
- this.$overlay = $('.mu-kids-overlay');
20
19
  this.$contextModalButton = new mumuki.Button($('.mu-kids-context .modal-footer button'));
21
20
 
22
21
  this._paragraphHeight = undefined;
@@ -58,6 +57,10 @@ mumuki.load(() => {
58
57
  this.showNonAbortedPopup(data, 'success2_l', 4000);
59
58
  }
60
59
 
60
+ _showPassedWithWarnings(data) {
61
+ this.showNonAbortedPopup(data, 'passed_with_warnings', 4000);
62
+ }
63
+
61
64
  _showFailurePopup(data) {
62
65
  this._showOnCharacterBubble(data);
63
66
  }
@@ -83,7 +86,7 @@ mumuki.load(() => {
83
86
  this._$texts.hide();
84
87
  this.$characterSpeechBubbleNormal.children('.' + $tab.data('target')).show();
85
88
  this._updateSpeechParagraphs();
86
- })
89
+ });
87
90
  }
88
91
  });
89
92
 
@@ -137,6 +140,7 @@ mumuki.load(() => {
137
140
  const $bubble = this.$characterSpeechBubble;
138
141
  Object.keys(this.resultActions).forEach($bubble.removeClass.bind($bubble));
139
142
  mumuki.presenterCharacter.playAnimation('talk', this.$bubbleCharacterAnimation);
143
+ this.hideOverlay();
140
144
  }
141
145
 
142
146
  // =======================
@@ -150,7 +154,6 @@ mumuki.load(() => {
150
154
  $bubble.find('.mu-kids-character-speech-bubble-failed').hide();
151
155
  $bubble.find('.mu-kids-discussion-link').remove();
152
156
  Object.keys(this.resultActions).forEach($bubble.removeClass.bind($bubble));
153
- this.$overlay.hide();
154
157
  }
155
158
 
156
159
  _showMessageOnCharacterBubble(data) {
@@ -158,7 +161,6 @@ mumuki.load(() => {
158
161
  renderer.setDiscussionsLinkHtml($('#mu-kids-discussion-link-html').html());
159
162
  renderer.setResponseData(data);
160
163
  renderer.render();
161
- this.$overlay.show();
162
164
  }
163
165
 
164
166
  _showOnCharacterBubble(data) {
@@ -17,7 +17,7 @@ mumuki.progress = (() => {
17
17
  function updateWholeProgressBar(f) {
18
18
  $('.progress-list-item').each((_, it) => {
19
19
  const $anchor = $(it);
20
- $anchor.attr('class', f($anchor))
20
+ $anchor.attr('class', f($anchor));
21
21
  });
22
22
  }
23
23
 
@@ -35,6 +35,32 @@ mumuki.renderers.results = (() => {
35
35
  }
36
36
  }
37
37
 
38
+ /**
39
+ * @param {SubmissionStatus} status
40
+ * @param {Boolean} isGamifiedContext
41
+ * @returns {string}
42
+ */
43
+ function translatedTitleHtml(status, isGamifiedContext) {
44
+ return `
45
+ <h4 class="text-${classForStatus(status)} %>">
46
+ <strong><i class="fa-fw fas ${iconForStatus(status)}"></i> ${mumuki.I18n.t(status)}</strong>
47
+ ${gamifiedContextHtml(isGamifiedContext)}
48
+ </h4>
49
+ `
50
+ }
51
+
52
+ /**
53
+ * @param {Boolean} isGamifiedContext
54
+ * @returns {string}
55
+ */
56
+ function gamifiedContextHtml(isGamifiedContext) {
57
+ return (!isGamifiedContext) ? '' : `
58
+ <strong><small class="text-success">
59
+ <span class="mu-experience"></span>
60
+ </small></strong>
61
+ `
62
+ }
63
+
38
64
 
39
65
  /**
40
66
  * @param {SubmissionStatus} status
@@ -48,8 +74,9 @@ mumuki.renderers.results = (() => {
48
74
  return {
49
75
  classForStatus,
50
76
  iconForStatus,
51
- progressListItemClassForStatus
52
- }
77
+ progressListItemClassForStatus,
78
+ translatedTitleHtml
79
+ };
53
80
  })();
54
81
 
55
82
  /** @deprecated use {@code mumuki.renderers.results.classForStatus} instead */
@@ -20,7 +20,7 @@ mumuki.renderers.speechBubble = (()=> {
20
20
 
21
21
  _chooseResultItem() {
22
22
  if (this._responseStatus() !== 'passed' && this._hasTips()) {
23
- this._appendFirstTip()
23
+ this._appendFirstTip();
24
24
  } else if (this._responseStatus() === 'failed') {
25
25
  this._appendFirstFailedTestResultSummary();
26
26
  } else if (this._responseStatus() === 'passed_with_warnings') {
@@ -29,7 +29,7 @@ mumuki.renderers.speechBubble = (()=> {
29
29
  }
30
30
 
31
31
  _appendFirstFailedTestResultSummary() {
32
- const failedTestResult = this._failedTestResults()[0]
32
+ const failedTestResult = this._failedTestResults()[0];
33
33
  if (failedTestResult && failedTestResult.summary) {
34
34
  this._appendResultItem(mumuki.renderers.renderSpeechBubbleResultItem(failedTestResult.summary));
35
35
  }
@@ -67,7 +67,7 @@ mumuki.renderers.speechBubble = (()=> {
67
67
  }
68
68
 
69
69
  _hasTips() {
70
- return this.responseData.tips && this.responseData.tips.length
70
+ return this.responseData.tips && this.responseData.tips.length;
71
71
  }
72
72
 
73
73
  _failedTestResults() {
@@ -97,7 +97,7 @@ mumuki.renderers.speechBubble = (()=> {
97
97
  return {
98
98
  SpeechBubbleRenderer,
99
99
  renderSpeechBubbleResultItem
100
- }
100
+ };
101
101
  })();
102
102
 
103
103
  /** @deprecated use {@code mumuki.renderers.speechBubble.SpeechBubbleRenderer} instead */
@@ -55,8 +55,50 @@ mumuki.submission = (() => {
55
55
  this.preventClick();
56
56
  }
57
57
  }
58
+
59
+ solutionSender(bridge, solution) {
60
+ return bridge._submitSolution(solution);
61
+ }
62
+
63
+ solutionProcessor(bridge, $submissionsResults, solution) {
64
+ const resultsBox = new ResultsBox($submissionsResults);
65
+ this.disable();
66
+ this.setWaitingText();
67
+ resultsBox.waiting();
68
+ return this.solutionSender(bridge, solution)
69
+ .done((data) => resultsBox.success(data, this))
70
+ .fail(() => resultsBox.error(this))
71
+ .always((data) => {
72
+ $(document).renderMuComponents();
73
+ resultsBox.done(data, this);
74
+ });
75
+ }
58
76
  }
59
77
 
78
+ class KidsSubmitButton extends SubmitButton {
79
+
80
+ wait() {
81
+ mumuki.kids.showOverlay();
82
+ super.wait();
83
+ }
84
+
85
+ continue() {
86
+ mumuki.kids.hideOverlay();
87
+ super.continue();
88
+ }
89
+
90
+ solutionProcessor(bridge, $submissionsResults, solution) {
91
+ this.wait();
92
+ return this.solutionSender(bridge, solution)
93
+ .then((data) => mumuki.kids.showResult(data))
94
+ .always((data) => {
95
+ this.ready(() => {
96
+ mumuki.kids.restart();
97
+ this.continue();
98
+ });
99
+ });
100
+ }
101
+ }
60
102
 
61
103
  // ==========
62
104
  // Processing
@@ -67,14 +109,28 @@ mumuki.submission = (() => {
67
109
  * restoring buttons state.
68
110
  *
69
111
  * The actual implementation of this method depends on contextual {@link _solutionProcessor}, which can
70
- * be configured using {@link _registerSolutionProcessor}. Currently there are only two available processors -
71
- * {@link _kidsSolutionProcessor} and {@link _classicSolutionProcessor} - which are automatically choosen depending
72
- * on the exercise DOM.
112
+ * be configured using {@link _registerSolutionProcessor}. Currently there are only two available processors
113
+ * which are automatically choosen depending on the exercise DOM.
73
114
  *
74
115
  * @param {Submission} solution
75
116
  */
76
117
  function processSolution(solution) {
77
- mumuki.submission._solutionProcessor(solution);
118
+ return mumuki.submission._solutionProcessor(solution);
119
+ }
120
+
121
+ /**
122
+ * Just sends solution to the server without any further processing afterwards.
123
+ *
124
+ * Consider using {@link processSolution} instead if you want the whole functionality (making buttons wait, sending to server, rendering results,
125
+ * restoring buttons state).
126
+ * The implementation of this method isn't contextual, it always sends the solution using bridge module.
127
+ *
128
+ * @see mumuki.bridge
129
+ *
130
+ * @param {Submission} solution
131
+ */
132
+ function sendSolution(solution) {
133
+ return mumuki.submission._solutionSender(solution);
78
134
  }
79
135
 
80
136
  /**
@@ -84,53 +140,19 @@ mumuki.submission = (() => {
84
140
  * and should normally not be called by runners editor, but is exposed
85
141
  * for further non-standard customizations.
86
142
  *
87
- * @param {({solution: object}) => void} processor
143
+ * @param {SubmitButton} submitButton
144
+ * @param {$ElementType} $submissionsResults
145
+ * @param {mumuki.bridge} bridge
88
146
  */
89
- function _registerSolutionProcessor(processor) {
90
- mumuki.submission._solutionProcessor = processor;
91
- }
92
-
93
- /** Processor for kids layouts */
94
- function _kidsSolutionProcessor(bridge, submitButton) {
95
- return (solution) => {
96
- submitButton.wait();
97
- bridge._submitSolution(solution).always(function (data) {
98
- submitButton.ready(() => {
99
- mumuki.kids.restart();
100
- submitButton.continue();
101
- });
102
- mumuki.kids.showResult(data);
103
- });
104
- }
105
- }
106
-
107
- /** Processor for non-kids layouts */
108
- function _classicSolutionProcessor(bridge, submitButton, resultsBox) {
109
- return (solution) => {
110
- submitButton.disable();
111
- submitButton.setWaitingText();
112
- resultsBox.waiting();
113
- bridge._submitSolution(solution).done(function (data) {
114
- resultsBox.success(data, submitButton);
115
- }).fail(function () {
116
- resultsBox.error(submitButton);
117
- }).always(function (data) {
118
- $(document).renderMuComponents();
119
- resultsBox.done(data, submitButton);
120
- });
121
- }
147
+ function _registerSolutionProcessor(submitButton, $submissionsResults, bridge) {
148
+ mumuki.submission._solutionSender = submitButton.solutionSender.bind(submitButton, bridge);
149
+ mumuki.submission._solutionProcessor = submitButton.solutionProcessor.bind(submitButton, bridge, $submissionsResults);
122
150
  }
123
151
 
124
152
  /** Selects the most appropriate solution processor */
125
153
  function _selectSolutionProcessor(submitButton, $submissionsResults) {
126
154
  const bridge = new mumuki.bridge.Laboratory();
127
- let processor;
128
- if ($('.mu-kids-exercise').length) {
129
- processor = _kidsSolutionProcessor(bridge, submitButton);
130
- } else {
131
- processor = _classicSolutionProcessor(bridge, submitButton, new ResultsBox($submissionsResults));
132
- }
133
- mumuki.submission._registerSolutionProcessor(processor);
155
+ mumuki.submission._registerSolutionProcessor(submitButton, $submissionsResults, bridge);
134
156
  }
135
157
 
136
158
 
@@ -143,8 +165,8 @@ mumuki.submission = (() => {
143
165
  if (!$submissionsResults) return;
144
166
 
145
167
  const $btnSubmit = $('.btn-submit');
146
- const submitButton = new SubmitButton($btnSubmit, $('.submission_control'));
147
-
168
+ const buttonClass = mumuki.isKidsExercise() ? KidsSubmitButton : SubmitButton;
169
+ const submitButton = new buttonClass($btnSubmit, $('.submission_control'));
148
170
  mumuki.submission._selectSolutionProcessor(submitButton, $submissionsResults);
149
171
 
150
172
  submitButton.start(() => {
@@ -154,7 +176,6 @@ mumuki.submission = (() => {
154
176
  submitButton.checkAttemptsLeft();
155
177
  });
156
178
 
157
-
158
179
  /**
159
180
  * This module contains methods for submitting solution in at high level, dealing with network communication,
160
181
  * and layout-sensitive UI updates. It is intended to be both used internally by standard editors and by runners
@@ -171,10 +192,13 @@ mumuki.submission = (() => {
171
192
  */
172
193
  return {
173
194
  processSolution,
195
+ sendSolution,
196
+
174
197
  _registerSolutionProcessor,
175
198
  _selectSolutionProcessor,
176
199
 
177
200
  animateTimeoutError,
178
201
  SubmitButton,
202
+ KidsSubmitButton,
179
203
  };
180
204
  })();