rapid-router 5.18.0__py2.py3-none-any.whl → 7.6.8__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. example_project/rapid_router_test_settings.py +19 -7
  2. example_project/settings.py +21 -8
  3. example_project/urls.py +5 -6
  4. game/__init__.py +1 -1
  5. game/admin.py +7 -2
  6. game/character.py +8 -0
  7. game/decor.py +40 -0
  8. game/end_to_end_tests/base_game_test.py +34 -27
  9. game/end_to_end_tests/editor_page.py +15 -0
  10. game/end_to_end_tests/game_page.py +88 -20
  11. game/end_to_end_tests/selenium_test_case.py +1 -20
  12. game/end_to_end_tests/test_cow_crashes.py +3 -5
  13. game/end_to_end_tests/test_level_editor.py +273 -10
  14. game/end_to_end_tests/test_level_selection.py +25 -3
  15. game/end_to_end_tests/test_play_through.py +222 -127
  16. game/end_to_end_tests/test_python_levels.py +41 -7
  17. game/end_to_end_tests/test_saving_workspace.py +2 -1
  18. game/forms.py +7 -1
  19. game/level_management.py +26 -11
  20. game/messages.py +899 -337
  21. game/migrations/0001_squashed_0025_levels_ordering_pt1.py +19 -1
  22. game/migrations/0026_levels_pt2.py +13 -2
  23. game/migrations/0032_cannot_turn_left_level.py +13 -2
  24. game/migrations/0033_recursion_level.py +13 -2
  25. game/migrations/0034_joes_level.py +13 -2
  26. game/migrations/0035_disable_route_score_level_70.py +0 -2
  27. game/migrations/0036_level_score_73.py +0 -2
  28. game/migrations/0037_level_score_79.py +0 -2
  29. game/migrations/0038_level_score_40.py +0 -1
  30. game/migrations/0042_level_score_73.py +0 -2
  31. game/migrations/0048_add_cow_field_and_blocks.py +0 -2
  32. game/migrations/0049_level_score_34.py +0 -2
  33. game/migrations/0050_level_score_40.py +0 -2
  34. game/migrations/0051_level_score_49.py +0 -1
  35. game/migrations/0086_loop_levels.py +13 -2
  36. game/migrations/0092_disable_algo_score_in_custom_levels.py +28 -0
  37. game/migrations/0093_alter_level_character_name.py +18 -0
  38. game/migrations/0094_add_hint_lesson_subtitle_to_levels.py +28 -0
  39. game/migrations/0095_level_commands.py +18 -0
  40. game/migrations/0096_alter_level_commands.py +18 -0
  41. game/migrations/0097_add_python_den_levels.py +1515 -0
  42. game/migrations/0098_add_episode_link_fields.py +44 -0
  43. game/migrations/0099_python_episodes_links.py +103 -0
  44. game/migrations/0100_reorder_python_levels.py +179 -0
  45. game/migrations/0101_rename_episodes.py +45 -0
  46. game/migrations/0102_reoder_episodes_13_14.py +136 -0
  47. game/migrations/0103_level_1015_solution.py +26 -0
  48. game/migrations/0104_remove_level_direct_drive.py +17 -0
  49. game/migrations/0105_delete_invalid_attempts.py +18 -0
  50. game/migrations/0106_fields_to_snake_case.py +48 -0
  51. game/migrations/0107_rename_worksheet_link_episode_student_worksheet_link.py +18 -0
  52. game/migrations/0108_episode_indy_worksheet_link.py +18 -0
  53. game/migrations/0109_create_episodes_23_and_24.py +99 -0
  54. game/migrations/0110_remove_episode_indy_worksheet_link_and_more.py +100 -0
  55. game/migrations/0111_create_worksheets.py +149 -0
  56. game/migrations/0112_worksheet_locked_classes.py +21 -0
  57. game/migrations/0113_level_needs_approval.py +18 -0
  58. game/migrations/0114_default_and_non_student_levels_no_approval.py +31 -0
  59. game/migrations/0115_level_level__default_does_not_need_approval.py +22 -0
  60. game/migrations/0116_update_worksheet_video_links.py +68 -0
  61. game/migrations/0117_update_solutions_to_if_else.py +61 -0
  62. game/models.py +127 -17
  63. game/permissions.py +51 -19
  64. game/python_den_urls.py +26 -0
  65. game/random_road.py +9 -9
  66. game/serializers.py +12 -17
  67. game/static/django_reverse_js/js/reverse.js +171 -0
  68. game/static/game/css/LilitaOne-Regular.ttf +0 -0
  69. game/static/game/css/backgrounds.css +8 -12
  70. game/static/game/css/dataTables.custom.css +3 -2
  71. game/static/game/css/editor.css +47 -0
  72. game/static/game/css/game.css +37 -43
  73. game/static/game/css/game_screen.css +16 -0
  74. game/static/game/css/level_editor.css +5 -0
  75. game/static/game/css/level_selection.css +17 -2
  76. game/static/game/image/Python_Den_hero_student.png +0 -0
  77. game/static/game/image/Python_levels_page.svg +1954 -0
  78. game/static/game/image/characters/front_view/Electric_van.svg +448 -0
  79. game/static/game/image/characters/top_view/Electric_van.svg +448 -0
  80. game/static/game/image/decor/city/solar_panel.svg +1200 -0
  81. game/static/game/image/decor/farm/solar_panel.svg +86 -0
  82. game/static/game/image/decor/grass/solar_panel.svg +86 -0
  83. game/static/game/image/decor/snow/solar_panel.svg +173 -0
  84. game/static/game/image/electric_van.svg +448 -0
  85. game/static/game/image/icons/description.svg +1 -0
  86. game/static/game/image/icons/hint.svg +1 -0
  87. game/static/game/image/icons/python.svg +1 -1
  88. game/static/game/image/pigeon.svg +684 -0
  89. game/static/game/image/python_den_header.svg +19 -0
  90. game/static/game/js/animation.js +65 -24
  91. game/static/game/js/blockly/msg/js/bg.js +52 -1
  92. game/static/game/js/blockly/msg/js/ca.js +52 -1
  93. game/static/game/js/blockly/msg/js/en-gb.js +2 -0
  94. game/static/game/js/blockly/msg/js/en.js +2 -0
  95. game/static/game/js/blockly/msg/js/es.js +52 -1
  96. game/static/game/js/blockly/msg/js/fr.js +2 -0
  97. game/static/game/js/blockly/msg/js/hi.js +2 -0
  98. game/static/game/js/blockly/msg/js/it.js +52 -1
  99. game/static/game/js/blockly/msg/js/pl.js +52 -1
  100. game/static/game/js/blockly/msg/js/pt-br.js +52 -1
  101. game/static/game/js/blockly/msg/js/ru.js +52 -1
  102. game/static/game/js/blockly/msg/js/ur.js +52 -1
  103. game/static/game/js/blocklyCustomBlocks.js +93 -52
  104. game/static/game/js/button.js +12 -0
  105. game/static/game/js/cow.js +11 -7
  106. game/static/game/js/drawing.js +68 -29
  107. game/static/game/js/editor.js +23 -0
  108. game/static/game/js/game.js +74 -110
  109. game/static/game/js/level_editor.js +646 -274
  110. game/static/game/js/level_moderation.js +33 -2
  111. game/static/game/js/level_selection.js +1 -1
  112. game/static/game/js/loadLanguages.js +2 -2
  113. game/static/game/js/model.js +32 -2
  114. game/static/game/js/pythonControl.js +14 -1
  115. game/static/game/js/scoreboard.js +0 -37
  116. game/static/game/js/scoreboardSharedLevels.js +48 -0
  117. game/static/game/js/skulpt/skulpt-stdlib.js +1 -1
  118. game/static/game/js/sound.js +52 -5
  119. game/static/game/raphael_image/characters/top_view/Electric_van.svg +448 -0
  120. game/static/game/raphael_image/decor/city/solar_panel.svg +1200 -0
  121. game/static/game/raphael_image/decor/farm/solar_panel.svg +86 -0
  122. game/static/game/raphael_image/decor/grass/solar_panel.svg +86 -0
  123. game/static/game/raphael_image/decor/snow/solar_panel.svg +173 -0
  124. game/static/game/raphael_image/pigeon.svg +685 -0
  125. game/static/game/sass/game.scss +2 -2
  126. game/static/game/sound/clown_horn.mp3 +0 -0
  127. game/static/game/sound/clown_horn.ogg +0 -0
  128. game/static/game/sound/electric_van_starting.mp3 +0 -0
  129. game/static/game/sound/electric_van_starting.ogg +0 -0
  130. game/static/game/sound/pigeon.mp3 +0 -0
  131. game/static/game/sound/pigeon.ogg +0 -0
  132. game/static/game/sound/sleigh_bells.mp3 +0 -0
  133. game/static/game/sound/sleigh_bells.ogg +0 -0
  134. game/static/game/sound/sleigh_crash.mp3 +0 -0
  135. game/static/game/sound/sleigh_crash.ogg +0 -0
  136. game/templates/game/base.html +34 -14
  137. game/templates/game/basenonav.html +11 -5
  138. game/templates/game/game.html +142 -38
  139. game/templates/game/level_editor.html +340 -236
  140. game/templates/game/level_moderation.html +19 -6
  141. game/templates/game/level_selection.html +18 -110
  142. game/templates/game/python_den_level_selection.html +291 -0
  143. game/templates/game/python_den_worksheet.html +101 -0
  144. game/templates/game/scoreboard.html +83 -64
  145. game/tests/test_level_editor.py +94 -26
  146. game/tests/test_level_selection.py +149 -46
  147. game/tests/test_python_den_worksheet.py +85 -0
  148. game/tests/test_scoreboard.py +34 -7
  149. game/tests/utils/level.py +32 -26
  150. game/theme.py +5 -5
  151. game/urls.py +199 -61
  152. game/views/language_code_conversions.py +86 -86
  153. game/views/level.py +155 -63
  154. game/views/level_editor.py +88 -55
  155. game/views/level_moderation.py +23 -0
  156. game/views/level_selection.py +116 -47
  157. game/views/level_solutions.py +491 -106
  158. game/views/scoreboard.py +76 -51
  159. game/views/worksheet.py +25 -0
  160. rapid_router-7.6.8.dist-info/METADATA +174 -0
  161. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/RECORD +164 -104
  162. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/WHEEL +1 -1
  163. example_project/manage.py +0 -10
  164. game/static/game/image/actions/go.svg +0 -18
  165. game/static/game/js/js-reverse.js +0 -14
  166. game/static/game/js/pqselect.min.js +0 -9
  167. game/static/game/js/widget-scroller.js +0 -906
  168. rapid_router-5.18.0.dist-info/METADATA +0 -17
  169. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info/licenses}/LICENSE.md +0 -0
  170. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/top_level.txt +0 -0
@@ -6,11 +6,18 @@ ocargo.Game = function () {
6
6
  this.tabs = null
7
7
  this.failures = 0
8
8
  this.currentlySelectedTab = null
9
- this.isMuted = Cookies.get('muted') === 'true'
9
+
10
+ if (!hasFunctionalCookiesConsent()) {
11
+ deleteCookie('muted')
12
+ deleteCookie('preferredLanguage')
13
+ }
14
+ this.preferredLanguage = Cookies.get('preferredLanguage')
10
15
  }
11
16
 
12
17
  ocargo.Game.prototype.setup = function () {
13
- gameUpdateBlockLanguage(navigator.language.toLowerCase())
18
+ document.getElementById("language_dropdown").value = this.preferredLanguage ?? navigator.language.toLowerCase()
19
+ gameUpdateBlockLanguage(this.preferredLanguage ?? navigator.language.toLowerCase())
20
+ this.isMuted = Cookies.get('muted') ?? false
14
21
 
15
22
  if(new Date().getMonth() === 11) {
16
23
  $("#paper").css('background-color', '#eef7ff')
@@ -66,7 +73,6 @@ ocargo.Game.prototype.setup = function () {
66
73
  this._setupConsoleSliderListeners()
67
74
  this._setupPythonViewSliderListeners()
68
75
  this._setupConsoleLogViewSliderListeners()
69
- this._setupDirectDriveListeners()
70
76
  this._setupFuelGauge(ocargo.model.map.nodes, BLOCKS)
71
77
  this._setupTabs()
72
78
 
@@ -106,8 +112,16 @@ ocargo.Game.prototype.setup = function () {
106
112
  } else if (DEFAULT_LEVEL) {
107
113
  titlePrefix = gettext('Level %(level_name)s')
108
114
  }
115
+
116
+ let adjusted_level_name = ''
117
+ if (LEVEL_NAME > 1000) {
118
+ adjusted_level_name = LEVEL_NAME - 1000
119
+ } else {
120
+ adjusted_level_name = LEVEL_NAME;
121
+ }
122
+
109
123
  if (titlePrefix) {
110
- title = interpolate(titlePrefix, { level_name: LEVEL_NAME }, true)
124
+ title = interpolate(titlePrefix, { level_name: adjusted_level_name }, true)
111
125
  } else {
112
126
  title = LEVEL_NAME
113
127
  }
@@ -129,15 +143,19 @@ ocargo.Game.prototype.setup = function () {
129
143
 
130
144
  const showMascot = BLOCKLY_ENABLED && !PYTHON_VIEW_ENABLED && LEVEL_NAME <= 80; // show mascot on Blockly-only levels that are not above 80
131
145
 
146
+ const subtitle = SUBTITLE == "None" ? "" : "<b>" + SUBTITLE + "</b> <br> <br> ";
147
+ const next_button_html = NEXT_LEVEL_URL == "/pythonden/"
148
+ ? ocargo.button.episodeRedirectButtonHtml("next_button", NEXT_LEVEL_URL, gettext('Next episode'), NEXT_EPISODE)
149
+ : ocargo.button.dismissButtonHtml("next_button", gettext('Next level'))
132
150
  ocargo.Drawing.startPopup(
133
151
  title,
134
- LESSON,
152
+ subtitle + LESSON,
135
153
  message,
136
154
  showMascot,
137
155
  [
138
156
  ocargo.button.dismissButtonHtml("prev_button", gettext("Previous level")),
139
157
  ocargo.button.dismissButtonHtml('play_button', gettext('Play')),
140
- ocargo.button.dismissButtonHtml("next_button", gettext("Next level"))
158
+ next_button_html
141
159
  ]
142
160
  )
143
161
  }
@@ -170,6 +188,18 @@ ocargo.Game.prototype.reset = function () {
170
188
  }
171
189
 
172
190
  ocargo.Game.prototype.runProgramAndPrepareAnimation = function (blocks) {
191
+ if (window.location.href.startsWith("https://www.codeforlife.education")) {
192
+ if (window.location.href.includes("/pythonden/")) {
193
+ gtag("event", "python-den:level:play", {
194
+ levelId: LEVEL_NAME - 1000,
195
+ });
196
+ } else if (window.location.href.includes("/rapidrouter/")) {
197
+ gtag("event", "rapid-router:level:play", {
198
+ levelId: LEVEL_NAME,
199
+ });
200
+ }
201
+ }
202
+
173
203
  this.reset()
174
204
  let code = ocargo.pythonControl.getCode()
175
205
  ocargo.event.sendEvent('PlayButtonPressed', {
@@ -285,13 +315,18 @@ ocargo.Game.prototype.sendAttempt = function (score) {
285
315
 
286
316
  ocargo.Game.prototype.registerFailure = function () {
287
317
  this.failures += 1
288
- return this.failures >= 3
318
+ return this.failures >= 1
289
319
  }
290
320
 
291
321
  ocargo.Game.prototype._setupFuelGauge = function (nodes, blocks) {
292
322
  if (FUEL_GAUGE) {
293
- document.getElementById('fuelGauge').style.visibility = 'visible'
323
+ if (CHARACTER_NAME == "Electric van") {
324
+ document.getElementById("electricFuelGauge").style.visibility = "visible"
325
+ } else {
326
+ document.getElementById("fuelGauge").style.visibility = "visible"
327
+ }
294
328
 
329
+ // TODO: Investigate these for loops - are they necessary?
295
330
  for (var i = 0; i < blocks.length; i++) {
296
331
  if (blocks[i].type === 'turn_around' || blocks[i].type === 'wait') {
297
332
  return
@@ -306,44 +341,6 @@ ocargo.Game.prototype._setupFuelGauge = function (nodes, blocks) {
306
341
  }
307
342
  }
308
343
 
309
- ocargo.Game.prototype._setupDirectDriveListeners = function () {
310
- var manoeuvreCallback = function () {
311
- this.drawing.scrollToShowCharacter()
312
- this.onStopControls()
313
- }.bind(this)
314
-
315
- $('#moveForward').click(
316
- function () {
317
- if (ocargo.model.reasonForTermination != 'CRASH') {
318
- this.onPlayControls()
319
- ocargo.blocklyControl.addBlockToEndOfProgram('move_forwards')
320
- this.drawing.moveForward(manoeuvreCallback)
321
- }
322
- }.bind(this)
323
- )
324
- $('#turnLeft').click(
325
- function () {
326
- if (ocargo.model.reasonForTermination != 'CRASH') {
327
- this.onPlayControls()
328
- ocargo.blocklyControl.addBlockToEndOfProgram('turn_left')
329
- this.drawing.turnLeft(manoeuvreCallback)
330
- }
331
- }.bind(this)
332
- )
333
- $('#turnRight').click(
334
- function () {
335
- if (ocargo.model.reasonForTermination != 'CRASH') {
336
- this.onPlayControls()
337
- ocargo.blocklyControl.addBlockToEndOfProgram('turn_right')
338
- this.drawing.turnRight(manoeuvreCallback)
339
- }
340
- }.bind(this)
341
- )
342
- $('#go').click(function () {
343
- $('#play_radio').trigger('click')
344
- })
345
- }
346
-
347
344
  ocargo.Game.prototype._setupConsoleSliderListeners = function () {
348
345
  let tabsWidth = $('#tabs').width()
349
346
 
@@ -390,7 +387,6 @@ ocargo.Game.prototype._setupConsoleSliderListeners = function () {
390
387
  $('#consoleSlider').css('left', consoleSliderPosition + '%')
391
388
  $('#paper').css('width', 100 - consoleSliderPosition + '%')
392
389
  $('#tab_panes').css('width', consoleSliderPosition + '%')
393
- $('#direct_drive').css('left', consoleSliderPosition + '%')
394
390
 
395
391
  ocargo.blocklyControl.redrawBlockly()
396
392
  }
@@ -545,8 +541,6 @@ const buttonTransit = (buttonElementId, state) => {
545
541
  ocargo.Game.prototype.onPlayControls = function () {
546
542
  this.disallowCodeChanges()
547
543
 
548
- document.getElementById('direct_drive').style.visibility = 'hidden'
549
-
550
544
  this.tabs.play.transitTo('running')
551
545
  buttonTransit("run-code-button", "running")
552
546
  this.tabs.step.disable()
@@ -561,8 +555,6 @@ ocargo.Game.prototype.onPlayControls = function () {
561
555
  ocargo.Game.prototype.onStepControls = function () {
562
556
  this.disallowCodeChanges()
563
557
 
564
- document.getElementById('direct_drive').style.visibility = 'hidden'
565
-
566
558
  this.tabs.play.transitTo('paused')
567
559
  buttonTransit("run-code-button", "paused")
568
560
  this.tabs.step.disable()
@@ -576,8 +568,6 @@ ocargo.Game.prototype.onStepControls = function () {
576
568
  ocargo.Game.prototype.onFastControls = function () {
577
569
  this.disallowCodeChanges()
578
570
 
579
- document.getElementById('direct_drive').style.visibility = 'hidden'
580
-
581
571
  this.tabs.play.transitTo('running')
582
572
  buttonTransit("run-code-button", "running")
583
573
  this.tabs.fast.transitTo('fast')
@@ -592,8 +582,6 @@ ocargo.Game.prototype.onFastControls = function () {
592
582
  ocargo.Game.prototype.onSlowControls = function () {
593
583
  this.disallowCodeChanges()
594
584
 
595
- document.getElementById('direct_drive').style.visibility = 'hidden'
596
-
597
585
  this.tabs.play.transitTo('running')
598
586
  buttonTransit("run-code-button", "running")
599
587
  this.tabs.fast.transitTo('slow')
@@ -780,9 +768,6 @@ ocargo.Game.prototype.onPauseControls = function () {
780
768
  ocargo.Game.prototype.onStopControls = function () {
781
769
  this.allowCodeChanges()
782
770
 
783
- // TODO make this hidden unless blocks are clear or something...
784
- document.getElementById('direct_drive').style.visibility = 'visible'
785
-
786
771
  this.tabs.play.transitTo('readyToPlay')
787
772
  buttonTransit("run-code-button", "readyToPlay")
788
773
  this.tabs.fast.transitTo('slow')
@@ -837,9 +822,9 @@ ocargo.Game.prototype._setupPythonTab = function () {
837
822
  $('#consoleOutput').text('')
838
823
  }.bind(this)
839
824
  )
840
-
825
+ // --------- Commands for popup ---------------------------------------------------
841
826
  var leadMsg =
842
- '<p>' +
827
+ '<p style="font-size: 20px;">' +
843
828
  interpolate(
844
829
  gettext(
845
830
  'Run the following commands on the van object %(var_name)s, e.g. %(example)s'
@@ -848,52 +833,8 @@ ocargo.Game.prototype._setupPythonTab = function () {
848
833
  true
849
834
  ) +
850
835
  '</p>' +
851
- '<div class="row">' +
852
- '<div class="large-4 columns">' +
853
- '<p><b>' +
854
- gettext('Movement') +
855
- '</b>' +
856
- '<br>my_van.move_forwards()' +
857
- '<br>my_van.turn_left()' +
858
- '<br>my_van.turn_right()' +
859
- '<br>my_van.turn_around()' +
860
- '<br>my_van.wait()</p>' +
861
- '</div>' +
862
- '<div class="large-4 columns">' +
863
- '<p><b>' +
864
- gettext('Position') +
865
- '</b>' +
866
- '<br>my_van.at_dead_end()' +
867
- '<br>my_van.at_destination()' +
868
- '<br>my_van.at_red_traffic_light()' +
869
- '<br>my_van.at_green_traffic_light()' +
870
- '<br>my_van.at_traffic_light(c)' +
871
- '<br><i>' +
872
- interpolate(
873
- gettext("where %(arg_name)s is '%(red_color)s' or '%(green_color)s'"),
874
- { arg_name: 'c', red_color: 'RED', green_color: 'GREEN' },
875
- true
876
- ) +
877
- '</i></p>' +
878
- '</div>' +
879
- '<div class="large-4 columns">' +
880
- '<p>' +
881
- '<br>my_van.is_road_forward()' +
882
- '<br>my_van.is_road_left()' +
883
- '<br>my_van.is_road_right()' +
884
- '<br>my_van.is_road(d)' +
885
- '<br><i>' +
886
- interpolate(
887
- gettext(
888
- "where %(arg_name)s is '%(forward)s', '%(left)s', or '%(right)s'"
889
- ),
890
- { arg_name: 'd', forward: 'FORWARD', left: 'LEFT', right: 'RIGHT' },
891
- true
892
- ) +
893
- '</i></p>' +
894
- '</div>' +
895
- '</div>'
896
-
836
+ COMMANDS
837
+ // -----------------------------------------------------------------------------
897
838
  $('#van_commands_help').click(
898
839
  function (e) {
899
840
  ocargo.Drawing.startPopup(gettext('Python Commands'), leadMsg, '')
@@ -1223,7 +1164,7 @@ ocargo.Game.prototype._setupSaveTab = function () {
1223
1164
  python_contents: ocargo.pythonControl.getCode(),
1224
1165
  blockly_enabled: BLOCKLY_ENABLED,
1225
1166
  python_enabled: PYTHON_ENABLED,
1226
- pythonViewEnabled: PYTHON_VIEW_ENABLED
1167
+ python_view_enabled: PYTHON_VIEW_ENABLED
1227
1168
  }
1228
1169
 
1229
1170
  this.saving.saveWorkspace(
@@ -1382,21 +1323,44 @@ function restoreCmsLogin () {
1382
1323
  }
1383
1324
 
1384
1325
  function hasFunctionalCookiesConsent() {
1385
- return OnetrustActiveGroups && OnetrustActiveGroups.split(',').includes('C0003')
1326
+ try {
1327
+ return OnetrustActiveGroups.split(',').includes('C0003')
1328
+ } catch (e) {
1329
+ console.error(e)
1330
+ }
1331
+ return false
1386
1332
  }
1387
1333
 
1388
1334
  function setMutedCookie(mute) {
1389
1335
  if (hasFunctionalCookiesConsent()) {
1390
- Cookies.set('muted', mute.toString(), { path: Urls.levels() })
1336
+ if (mute) {
1337
+ Cookies.set('muted', true)
1338
+ }
1339
+ else {
1340
+ deleteCookie('muted')
1341
+ }
1391
1342
  }
1392
1343
  }
1393
1344
 
1394
- function gameUpdateBlockLanguage(language_code) {
1345
+ function deleteCookie(name) {
1346
+ // Set cookie expiry to yesterday, browser will remove the cookie.
1347
+ // https://www.quirksmode.org/js/cookies.html
1348
+ Cookies.set(name, "", { expires: -1 })
1349
+ }
1350
+
1351
+ function gameUpdateBlockLanguage (language_code) {
1395
1352
  loadLanguage("/static/game/js/blockly/msg/js/", language_code, function() {
1396
1353
  reloadWorkspace(Blockly.mainWorkspace);
1397
1354
  });
1398
1355
  }
1399
1356
 
1357
+ function gameUpdateBlockLanguageAndCookie (language_code) {
1358
+ if (hasFunctionalCookiesConsent()) {
1359
+ Cookies.set("preferredLanguage", language_code)
1360
+ }
1361
+ gameUpdateBlockLanguage(language_code)
1362
+ }
1363
+
1400
1364
  $(document).ready(function () {
1401
1365
  ocargo.game = new ocargo.Game()
1402
1366
  ocargo.game.setup()