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.
- example_project/rapid_router_test_settings.py +19 -7
- example_project/settings.py +21 -8
- example_project/urls.py +5 -6
- game/__init__.py +1 -1
- game/admin.py +7 -2
- game/character.py +8 -0
- game/decor.py +40 -0
- game/end_to_end_tests/base_game_test.py +34 -27
- game/end_to_end_tests/editor_page.py +15 -0
- game/end_to_end_tests/game_page.py +88 -20
- game/end_to_end_tests/selenium_test_case.py +1 -20
- game/end_to_end_tests/test_cow_crashes.py +3 -5
- game/end_to_end_tests/test_level_editor.py +273 -10
- game/end_to_end_tests/test_level_selection.py +25 -3
- game/end_to_end_tests/test_play_through.py +222 -127
- game/end_to_end_tests/test_python_levels.py +41 -7
- game/end_to_end_tests/test_saving_workspace.py +2 -1
- game/forms.py +7 -1
- game/level_management.py +26 -11
- game/messages.py +899 -337
- game/migrations/0001_squashed_0025_levels_ordering_pt1.py +19 -1
- game/migrations/0026_levels_pt2.py +13 -2
- game/migrations/0032_cannot_turn_left_level.py +13 -2
- game/migrations/0033_recursion_level.py +13 -2
- game/migrations/0034_joes_level.py +13 -2
- game/migrations/0035_disable_route_score_level_70.py +0 -2
- game/migrations/0036_level_score_73.py +0 -2
- game/migrations/0037_level_score_79.py +0 -2
- game/migrations/0038_level_score_40.py +0 -1
- game/migrations/0042_level_score_73.py +0 -2
- game/migrations/0048_add_cow_field_and_blocks.py +0 -2
- game/migrations/0049_level_score_34.py +0 -2
- game/migrations/0050_level_score_40.py +0 -2
- game/migrations/0051_level_score_49.py +0 -1
- game/migrations/0086_loop_levels.py +13 -2
- game/migrations/0092_disable_algo_score_in_custom_levels.py +28 -0
- game/migrations/0093_alter_level_character_name.py +18 -0
- game/migrations/0094_add_hint_lesson_subtitle_to_levels.py +28 -0
- game/migrations/0095_level_commands.py +18 -0
- game/migrations/0096_alter_level_commands.py +18 -0
- game/migrations/0097_add_python_den_levels.py +1515 -0
- game/migrations/0098_add_episode_link_fields.py +44 -0
- game/migrations/0099_python_episodes_links.py +103 -0
- game/migrations/0100_reorder_python_levels.py +179 -0
- game/migrations/0101_rename_episodes.py +45 -0
- game/migrations/0102_reoder_episodes_13_14.py +136 -0
- game/migrations/0103_level_1015_solution.py +26 -0
- game/migrations/0104_remove_level_direct_drive.py +17 -0
- game/migrations/0105_delete_invalid_attempts.py +18 -0
- game/migrations/0106_fields_to_snake_case.py +48 -0
- game/migrations/0107_rename_worksheet_link_episode_student_worksheet_link.py +18 -0
- game/migrations/0108_episode_indy_worksheet_link.py +18 -0
- game/migrations/0109_create_episodes_23_and_24.py +99 -0
- game/migrations/0110_remove_episode_indy_worksheet_link_and_more.py +100 -0
- game/migrations/0111_create_worksheets.py +149 -0
- game/migrations/0112_worksheet_locked_classes.py +21 -0
- game/migrations/0113_level_needs_approval.py +18 -0
- game/migrations/0114_default_and_non_student_levels_no_approval.py +31 -0
- game/migrations/0115_level_level__default_does_not_need_approval.py +22 -0
- game/migrations/0116_update_worksheet_video_links.py +68 -0
- game/migrations/0117_update_solutions_to_if_else.py +61 -0
- game/models.py +127 -17
- game/permissions.py +51 -19
- game/python_den_urls.py +26 -0
- game/random_road.py +9 -9
- game/serializers.py +12 -17
- game/static/django_reverse_js/js/reverse.js +171 -0
- game/static/game/css/LilitaOne-Regular.ttf +0 -0
- game/static/game/css/backgrounds.css +8 -12
- game/static/game/css/dataTables.custom.css +3 -2
- game/static/game/css/editor.css +47 -0
- game/static/game/css/game.css +37 -43
- game/static/game/css/game_screen.css +16 -0
- game/static/game/css/level_editor.css +5 -0
- game/static/game/css/level_selection.css +17 -2
- game/static/game/image/Python_Den_hero_student.png +0 -0
- game/static/game/image/Python_levels_page.svg +1954 -0
- game/static/game/image/characters/front_view/Electric_van.svg +448 -0
- game/static/game/image/characters/top_view/Electric_van.svg +448 -0
- game/static/game/image/decor/city/solar_panel.svg +1200 -0
- game/static/game/image/decor/farm/solar_panel.svg +86 -0
- game/static/game/image/decor/grass/solar_panel.svg +86 -0
- game/static/game/image/decor/snow/solar_panel.svg +173 -0
- game/static/game/image/electric_van.svg +448 -0
- game/static/game/image/icons/description.svg +1 -0
- game/static/game/image/icons/hint.svg +1 -0
- game/static/game/image/icons/python.svg +1 -1
- game/static/game/image/pigeon.svg +684 -0
- game/static/game/image/python_den_header.svg +19 -0
- game/static/game/js/animation.js +65 -24
- game/static/game/js/blockly/msg/js/bg.js +52 -1
- game/static/game/js/blockly/msg/js/ca.js +52 -1
- game/static/game/js/blockly/msg/js/en-gb.js +2 -0
- game/static/game/js/blockly/msg/js/en.js +2 -0
- game/static/game/js/blockly/msg/js/es.js +52 -1
- game/static/game/js/blockly/msg/js/fr.js +2 -0
- game/static/game/js/blockly/msg/js/hi.js +2 -0
- game/static/game/js/blockly/msg/js/it.js +52 -1
- game/static/game/js/blockly/msg/js/pl.js +52 -1
- game/static/game/js/blockly/msg/js/pt-br.js +52 -1
- game/static/game/js/blockly/msg/js/ru.js +52 -1
- game/static/game/js/blockly/msg/js/ur.js +52 -1
- game/static/game/js/blocklyCustomBlocks.js +93 -52
- game/static/game/js/button.js +12 -0
- game/static/game/js/cow.js +11 -7
- game/static/game/js/drawing.js +68 -29
- game/static/game/js/editor.js +23 -0
- game/static/game/js/game.js +74 -110
- game/static/game/js/level_editor.js +646 -274
- game/static/game/js/level_moderation.js +33 -2
- game/static/game/js/level_selection.js +1 -1
- game/static/game/js/loadLanguages.js +2 -2
- game/static/game/js/model.js +32 -2
- game/static/game/js/pythonControl.js +14 -1
- game/static/game/js/scoreboard.js +0 -37
- game/static/game/js/scoreboardSharedLevels.js +48 -0
- game/static/game/js/skulpt/skulpt-stdlib.js +1 -1
- game/static/game/js/sound.js +52 -5
- game/static/game/raphael_image/characters/top_view/Electric_van.svg +448 -0
- game/static/game/raphael_image/decor/city/solar_panel.svg +1200 -0
- game/static/game/raphael_image/decor/farm/solar_panel.svg +86 -0
- game/static/game/raphael_image/decor/grass/solar_panel.svg +86 -0
- game/static/game/raphael_image/decor/snow/solar_panel.svg +173 -0
- game/static/game/raphael_image/pigeon.svg +685 -0
- game/static/game/sass/game.scss +2 -2
- game/static/game/sound/clown_horn.mp3 +0 -0
- game/static/game/sound/clown_horn.ogg +0 -0
- game/static/game/sound/electric_van_starting.mp3 +0 -0
- game/static/game/sound/electric_van_starting.ogg +0 -0
- game/static/game/sound/pigeon.mp3 +0 -0
- game/static/game/sound/pigeon.ogg +0 -0
- game/static/game/sound/sleigh_bells.mp3 +0 -0
- game/static/game/sound/sleigh_bells.ogg +0 -0
- game/static/game/sound/sleigh_crash.mp3 +0 -0
- game/static/game/sound/sleigh_crash.ogg +0 -0
- game/templates/game/base.html +34 -14
- game/templates/game/basenonav.html +11 -5
- game/templates/game/game.html +142 -38
- game/templates/game/level_editor.html +340 -236
- game/templates/game/level_moderation.html +19 -6
- game/templates/game/level_selection.html +18 -110
- game/templates/game/python_den_level_selection.html +291 -0
- game/templates/game/python_den_worksheet.html +101 -0
- game/templates/game/scoreboard.html +83 -64
- game/tests/test_level_editor.py +94 -26
- game/tests/test_level_selection.py +149 -46
- game/tests/test_python_den_worksheet.py +85 -0
- game/tests/test_scoreboard.py +34 -7
- game/tests/utils/level.py +32 -26
- game/theme.py +5 -5
- game/urls.py +199 -61
- game/views/language_code_conversions.py +86 -86
- game/views/level.py +155 -63
- game/views/level_editor.py +88 -55
- game/views/level_moderation.py +23 -0
- game/views/level_selection.py +116 -47
- game/views/level_solutions.py +491 -106
- game/views/scoreboard.py +76 -51
- game/views/worksheet.py +25 -0
- rapid_router-7.6.8.dist-info/METADATA +174 -0
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/RECORD +164 -104
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/WHEEL +1 -1
- example_project/manage.py +0 -10
- game/static/game/image/actions/go.svg +0 -18
- game/static/game/js/js-reverse.js +0 -14
- game/static/game/js/pqselect.min.js +0 -9
- game/static/game/js/widget-scroller.js +0 -906
- rapid_router-5.18.0.dist-info/METADATA +0 -17
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info/licenses}/LICENSE.md +0 -0
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/top_level.txt +0 -0
|
@@ -34,13 +34,14 @@
|
|
|
34
34
|
<div class="background">
|
|
35
35
|
<div class="container">
|
|
36
36
|
<div>
|
|
37
|
-
<h4>Level moderation</
|
|
37
|
+
<h4>Level moderation</h4>
|
|
38
38
|
<p>Search or filter the levels to find specific details, and click 'Play' to view the games.</p>
|
|
39
|
+
<p>You can approve or delete any level.</p>
|
|
39
40
|
|
|
40
41
|
<form action="" method="post" id="moderateForm">
|
|
41
42
|
{% csrf_token %}
|
|
42
43
|
<div class="row form--row">
|
|
43
|
-
<div class="col-sm-
|
|
44
|
+
<div class="col-sm-6">
|
|
44
45
|
<div class="dropdown">
|
|
45
46
|
<button class="button--secondary button--secondary--dark button--dropdown" type="button" data-toggle="dropdown" aria-expanded="false">
|
|
46
47
|
<div class="dropdown__text">Filter classes</div>
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
</div>
|
|
77
78
|
</div>
|
|
78
79
|
</div>
|
|
79
|
-
<div class="form--row__input col-sm-
|
|
80
|
+
<div class="form--row__input col-sm-6">
|
|
80
81
|
<div class="input--icon">
|
|
81
82
|
<input type="text" name="Search" placeholder="Search" id="moderateSearch"><span class="iconify" data-icon="mdi:search"></span>
|
|
82
83
|
</div>
|
|
@@ -89,7 +90,7 @@
|
|
|
89
90
|
<div class="mainBody container">
|
|
90
91
|
{% include "portal/partials/popup.html" %}
|
|
91
92
|
{% if levelData %}
|
|
92
|
-
<div class="tableWrapper">
|
|
93
|
+
<div class="tableWrapper" id="tableWrapper">
|
|
93
94
|
{% if thead %}
|
|
94
95
|
<table id="moderateTable" class="header-primary data-primary">
|
|
95
96
|
<thead>
|
|
@@ -97,11 +98,12 @@
|
|
|
97
98
|
<th rowspan="2">Student</th>
|
|
98
99
|
<th rowspan="2">Level name</th>
|
|
99
100
|
<th rowspan="2">Shared with</th>
|
|
100
|
-
<th colspan="
|
|
101
|
+
<th colspan="3">Actions</th>
|
|
101
102
|
</tr>
|
|
102
103
|
<!-- Extra header only needed for DataTables - should be hidden to the user -->
|
|
103
104
|
<tr class="d-none">
|
|
104
105
|
<th>Play</th>
|
|
106
|
+
<th>Approve</th>
|
|
105
107
|
<th>Delete</th>
|
|
106
108
|
</tr>
|
|
107
109
|
</thead>
|
|
@@ -113,7 +115,18 @@
|
|
|
113
115
|
<td><small>{{level.name}}</small></td>
|
|
114
116
|
<td><small>{{level.shared_with}}</small></td>
|
|
115
117
|
<td class="text-center">
|
|
116
|
-
<
|
|
118
|
+
<a class="button button--small button--primary play" href="{% url 'play_custom_level' level.id %}">Play</a>
|
|
119
|
+
</td>
|
|
120
|
+
<td class="text-center">
|
|
121
|
+
{% if level.needs_approval %}
|
|
122
|
+
<button class="button button--small button--primary approve" value={{level.id}}>
|
|
123
|
+
Approve
|
|
124
|
+
</button>
|
|
125
|
+
{% else %}
|
|
126
|
+
<button class="button button--small button--primary disabled button--icon">
|
|
127
|
+
Approved<span class="iconify" data-icon="mdi:tick"></span>
|
|
128
|
+
</button>
|
|
129
|
+
{% endif %}
|
|
117
130
|
</td>
|
|
118
131
|
<td class="text-center">
|
|
119
132
|
<button class="button button--small button--primary--danger button--icon delete" value={{level.id}}>
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
EPISODES.push({'id' : {{episode.id}}, 'levels': levels});
|
|
21
21
|
{% endfor %}
|
|
22
22
|
|
|
23
|
-
{% for episode in
|
|
23
|
+
{% for episode in oldPythonEpisodes %}
|
|
24
24
|
var levels = [];
|
|
25
25
|
{% for level in episode.levels %}
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
levels.push({
|
|
27
|
+
'name': {{level.name}},
|
|
28
28
|
'score': '{{level.score}}',
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
'maxScore': {{level.maxScore}}
|
|
30
|
+
});
|
|
31
31
|
{% endfor %}
|
|
32
32
|
EPISODES.push({'id' : {{episode.id}}, 'levels': levels});
|
|
33
33
|
{% endfor %}
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
{% endfor %}
|
|
42
42
|
</script>
|
|
43
43
|
|
|
44
|
-
<script src="{% static
|
|
44
|
+
<script src="{% static 'game/js/level_selection.js' %}"></script>
|
|
45
45
|
{% endblock %}
|
|
46
46
|
|
|
47
47
|
{% block css %}
|
|
@@ -71,8 +71,9 @@
|
|
|
71
71
|
<div id="episodes">
|
|
72
72
|
<div class="panel-intro">
|
|
73
73
|
<h4>Blockly levels</h4>
|
|
74
|
-
The first set of levels use Blockly to slowly introduce you to
|
|
75
|
-
|
|
74
|
+
The first set of levels use Blockly to slowly introduce you to
|
|
75
|
+
core programming concepts. You can read more about Blockly
|
|
76
|
+
<a href="https://code-for-life.gitbook.io/rapid-router/blockly-guide" target="_blank">here</a>.
|
|
76
77
|
</div>
|
|
77
78
|
{% for episode in blocklyEpisodes %}
|
|
78
79
|
<div class="panel">
|
|
@@ -88,6 +89,9 @@
|
|
|
88
89
|
|
|
89
90
|
<div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
|
|
90
91
|
<div class="panel-body">
|
|
92
|
+
{% if not user.is_authenticated and episode.id > 2 %}
|
|
93
|
+
<p class="text--warning">In order to access the full content for this course, please log in.</p>
|
|
94
|
+
{% endif %}
|
|
91
95
|
{% for level in episode.levels %}
|
|
92
96
|
{% if user|is_logged_in_as_student and user.new_student.class_field in level.locked_for_class.all %}
|
|
93
97
|
<!-- Mark level as locked -->
|
|
@@ -98,6 +102,11 @@
|
|
|
98
102
|
<img class="level_image coin_image" value="{{level.name}}">
|
|
99
103
|
{% endif %}
|
|
100
104
|
</p>
|
|
105
|
+
{% elif not user.is_authenticated and level.name > 19 and level.name != 29 and level.name != 33 and level.name != 44 and level.name != 51 and level.name != 61 and level.name != 68 %}
|
|
106
|
+
<!-- Mark level as locked -->
|
|
107
|
+
<p>
|
|
108
|
+
<a class="disabled">{{level.name}}: {{level.title.strip | safe}}</a>
|
|
109
|
+
</p>
|
|
101
110
|
{% else %}
|
|
102
111
|
<!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
|
|
103
112
|
<p>
|
|
@@ -110,7 +119,7 @@
|
|
|
110
119
|
{% endif %}
|
|
111
120
|
{% endfor %}
|
|
112
121
|
|
|
113
|
-
{% if episode.random_levels_enabled %}
|
|
122
|
+
{% if not user.is_authenticated and episode.id <= 2 or user.is_authenticated and episode.random_levels_enabled %}
|
|
114
123
|
<p>
|
|
115
124
|
<a href="{% url 'random_level_for_episode' episode.id %}">
|
|
116
125
|
Random: Try your hand at a random level
|
|
@@ -122,107 +131,6 @@
|
|
|
122
131
|
</div>
|
|
123
132
|
{% endfor %}
|
|
124
133
|
|
|
125
|
-
<div class="panel-intro">
|
|
126
|
-
<h4>Python levels</h4>
|
|
127
|
-
The next set of levels introduce you to coding directly with Python. You can read more about Python
|
|
128
|
-
<a href="https://docs.codeforlife.education/rapid-router/python-guide" target="_blank">here</a>.
|
|
129
|
-
</div>
|
|
130
|
-
{% for episode in pythonEpisodes %}
|
|
131
|
-
{% if episode.difficulty != "loops" %}
|
|
132
|
-
<div class="panel">
|
|
133
|
-
<div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
|
|
134
|
-
<p class="episode-title" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
135
|
-
{{episode.name}}
|
|
136
|
-
<span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
137
|
-
Levels {{episode.first_level}}-{{episode.last_level}}
|
|
138
|
-
</span>
|
|
139
|
-
<img class="episode_image coin_image" value="{{episode.id}}">
|
|
140
|
-
</p>
|
|
141
|
-
</div>
|
|
142
|
-
|
|
143
|
-
<div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
|
|
144
|
-
<div class="panel-body">
|
|
145
|
-
{% for level in episode.levels %}
|
|
146
|
-
{% if user|is_logged_in_as_student and user.new_student.class_field in level.locked_for_class.all %}
|
|
147
|
-
<!-- Mark level as locked -->
|
|
148
|
-
<p>
|
|
149
|
-
<a class="disabled">{{level.name}}: {{level.title.strip | safe}}</a>
|
|
150
|
-
{% if level.score != None %}
|
|
151
|
-
<span class="score_text disabled">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
|
|
152
|
-
<img class="level_image coin_image" value="{{level.name}}">
|
|
153
|
-
{% endif %}
|
|
154
|
-
</p>
|
|
155
|
-
{% else %}
|
|
156
|
-
<!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
|
|
157
|
-
<p>
|
|
158
|
-
<a href="{% url 'play_default_level' level.name %}">{{level.name}}: {{level.title.strip | safe}}</a>
|
|
159
|
-
{% if level.score != None %}
|
|
160
|
-
<span class="score_text">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
|
|
161
|
-
<img class="level_image coin_image" value="{{level.name}}">
|
|
162
|
-
{% endif %}
|
|
163
|
-
</p>
|
|
164
|
-
{% endif %}
|
|
165
|
-
{% endfor %}
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
{% endif %}
|
|
170
|
-
{% endfor %}
|
|
171
|
-
<div class="panel-subintro">
|
|
172
|
-
The following levels focus on Loops using Blockly and Python.
|
|
173
|
-
</div>
|
|
174
|
-
{% for episode in pythonEpisodes %}
|
|
175
|
-
{% if episode.difficulty == "loops" %}
|
|
176
|
-
<div
|
|
177
|
-
class="panel"
|
|
178
|
-
{% if "coming soon" in episode.name %}
|
|
179
|
-
style="pointer-events:none;"
|
|
180
|
-
{% endif %}
|
|
181
|
-
>
|
|
182
|
-
<div {% if "coming soon" in episode.name %}
|
|
183
|
-
class="panel-header bg--loops-coming-soon"
|
|
184
|
-
{% else %}
|
|
185
|
-
class="panel-header bg--{{ episode.difficulty }}"
|
|
186
|
-
{% endif %}
|
|
187
|
-
id="episode-{{episode.id}}">
|
|
188
|
-
<p class="episode-title" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
189
|
-
{{episode.name}}
|
|
190
|
-
<span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
191
|
-
Levels {{episode.first_level}}-{{episode.last_level}}
|
|
192
|
-
</span>
|
|
193
|
-
<img class="episode_image coin_image" value="{{episode.id}}">
|
|
194
|
-
</p>
|
|
195
|
-
</div>
|
|
196
|
-
|
|
197
|
-
<div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
|
|
198
|
-
<div class="panel-body">
|
|
199
|
-
{% for level in episode.levels %}
|
|
200
|
-
{% if user|is_logged_in_as_student and user.new_student.class_field in level.locked_for_class.all %}
|
|
201
|
-
<!-- Mark level as locked -->
|
|
202
|
-
<p>
|
|
203
|
-
<a class="disabled">{{level.name}}: {{level.title.strip | safe}}</a>
|
|
204
|
-
{% if level.score != None %}
|
|
205
|
-
<span class="score_text disabled">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
|
|
206
|
-
<img class="level_image coin_image" value="{{level.name}}">
|
|
207
|
-
{% endif %}
|
|
208
|
-
</p>
|
|
209
|
-
{% else %}
|
|
210
|
-
<!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
|
|
211
|
-
<p>
|
|
212
|
-
<a href="{% url 'play_default_level' level.name %}">{{level.name}}: {{level.title.strip | safe}}</a>
|
|
213
|
-
{% if level.score != None %}
|
|
214
|
-
<span class="score_text">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
|
|
215
|
-
<img class="level_image coin_image" value="{{level.name}}">
|
|
216
|
-
{% endif %}
|
|
217
|
-
</p>
|
|
218
|
-
{% endif %}
|
|
219
|
-
{% endfor %}
|
|
220
|
-
</div>
|
|
221
|
-
</div>
|
|
222
|
-
</div>
|
|
223
|
-
{% endif %}
|
|
224
|
-
{% endfor %}
|
|
225
|
-
|
|
226
134
|
{% if user|is_logged_in %}
|
|
227
135
|
<div class="panel-intro">
|
|
228
136
|
<h4>Created levels</h4>
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
{% extends 'game/base.html' %}
|
|
2
|
+
|
|
3
|
+
{% load static %}
|
|
4
|
+
{% load i18n %}
|
|
5
|
+
{% load app_tags %}
|
|
6
|
+
|
|
7
|
+
{% block scripts %}
|
|
8
|
+
{{block.super}}
|
|
9
|
+
<script>
|
|
10
|
+
var EPISODES = [];
|
|
11
|
+
|
|
12
|
+
{% for episode in pythonEpisodes %}
|
|
13
|
+
var levels = [];
|
|
14
|
+
{% for level in episode.levels %}
|
|
15
|
+
levels.push({
|
|
16
|
+
'name': {{level.name}},
|
|
17
|
+
'score': '{{level.score}}',
|
|
18
|
+
'maxScore': {{level.maxScore}}
|
|
19
|
+
});
|
|
20
|
+
{% endfor %}
|
|
21
|
+
EPISODES.push({'id' : {{episode.id}}, 'levels': levels});
|
|
22
|
+
{% endfor %}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<script src="{% static 'game/js/level_selection.js' %}"></script>
|
|
26
|
+
{% endblock %}
|
|
27
|
+
|
|
28
|
+
{% block css %}
|
|
29
|
+
{{block.super}}
|
|
30
|
+
<link href="{% static 'game/css/level_selection.css' %}" rel="stylesheet" type="text/css">
|
|
31
|
+
{% endblock %}
|
|
32
|
+
|
|
33
|
+
{% block header %}
|
|
34
|
+
<section class="banner">
|
|
35
|
+
{% if user|is_logged_in_as_student or user|is_independent_student %}
|
|
36
|
+
<img class="banner--python-den--image" title="Python Den logo" alt="Python Den logo" src="{% static 'game/image/Python_Den_hero_student.png' %}">
|
|
37
|
+
{% else %}
|
|
38
|
+
<img class="banner--python-den--image" title="Python Den logo" alt="Python Den logo" src="{% static 'game/image/Python_levels_page.svg' %}">
|
|
39
|
+
{% endif %}
|
|
40
|
+
</section>
|
|
41
|
+
{% endblock header %}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
{% block nav_ocargo_levels %}
|
|
45
|
+
{% if user|is_logged_in_as_student %}
|
|
46
|
+
<a class="button button--secondary button--secondary--light sub-nav--student-active">Levels</a>
|
|
47
|
+
{% elif user|is_independent_student %}
|
|
48
|
+
<a class="button button--secondary sub-nav--independent-active">Levels</a>
|
|
49
|
+
{% else %}
|
|
50
|
+
<a class="button button--secondary button--secondary--light sub-nav--teacher-active">Levels</a>
|
|
51
|
+
{% endif %}
|
|
52
|
+
{% endblock nav_ocargo_levels %}
|
|
53
|
+
|
|
54
|
+
{% block content %}
|
|
55
|
+
<div class="container background">
|
|
56
|
+
<div id="episodes">
|
|
57
|
+
<div class="panel-intro">
|
|
58
|
+
<h4>Introduction to Python</h4>
|
|
59
|
+
Python lessons using split-screen Blockly/Python and an online IDE for programming lessons in Python.
|
|
60
|
+
We have created free editable plans, presentations, and worksheets to support these lessons.
|
|
61
|
+
</div>
|
|
62
|
+
{% for episode in pythonEpisodes %}
|
|
63
|
+
{% if episode.difficulty != "late-python" %}
|
|
64
|
+
<div class="panel">
|
|
65
|
+
<div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
|
|
66
|
+
<p class="episode-title" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
67
|
+
{{episode.name}}
|
|
68
|
+
<span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes"></span>
|
|
69
|
+
</p>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
|
|
73
|
+
<div class="panel-body">
|
|
74
|
+
{% for worksheet in episode.worksheets %}
|
|
75
|
+
{% if not user|is_logged_in or user.new_student.class_field in worksheet.locked_classes.all %}
|
|
76
|
+
{% if not user|is_logged_in %}
|
|
77
|
+
<p class="text--warning">In order to access the full content for this course, please log in.</p>
|
|
78
|
+
{% endif %}
|
|
79
|
+
<div class="col-sm-10 python-den-level">
|
|
80
|
+
<a class="disabled">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="col-sm-2 python-den-level">
|
|
83
|
+
<a class="button button--level button--icon disabled">
|
|
84
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
85
|
+
</div>
|
|
86
|
+
{% else %}
|
|
87
|
+
<div class="col-sm-7 python-den-level">
|
|
88
|
+
<a href="{% url 'worksheet' worksheet.id %}">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
|
|
89
|
+
</div>
|
|
90
|
+
{% if user|is_logged_in_as_teacher %}
|
|
91
|
+
<div class="col-sm-3 python-den-level">
|
|
92
|
+
<a href="{{worksheet.lesson_plan_link}}" class="button button--level button--icon" target="_blank">
|
|
93
|
+
Lesson plan<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="col-sm-2 python-den-level">
|
|
96
|
+
<a href="{{worksheet.slides_link}}" class="button button--level button--icon" target="_blank">
|
|
97
|
+
Slides<span class="iconify" data-icon="mdi:tray-arrow-down"></span></a>
|
|
98
|
+
</div>
|
|
99
|
+
{% elif user|is_independent_student %}
|
|
100
|
+
<div class="col-sm-3 python-den-level">
|
|
101
|
+
<a href="{{worksheet.indy_worksheet_link}}" class="button button--level button--icon" target="_blank">
|
|
102
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="col-sm-2 python-den-level">
|
|
105
|
+
<a href="{{worksheet.video_link}}" class="button button--level button--icon" target="_blank">
|
|
106
|
+
Video<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
107
|
+
</div>
|
|
108
|
+
{% else %}
|
|
109
|
+
<div class="col-sm-3"></div>
|
|
110
|
+
<div class="col-sm-2 python-den-level">
|
|
111
|
+
<a href="{{worksheet.student_worksheet_link}}" class="button button--level button--icon" target="_blank">
|
|
112
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
113
|
+
</div>
|
|
114
|
+
{% endif %}
|
|
115
|
+
{% endif %}
|
|
116
|
+
{% endfor %}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
{% endif %}
|
|
121
|
+
{% endfor %}
|
|
122
|
+
<div class="panel-subintro">
|
|
123
|
+
This section introduces Python using a mix of Blockly split screen and text based programming.
|
|
124
|
+
</div>
|
|
125
|
+
{% for episode in pythonEpisodes %}
|
|
126
|
+
{% if episode.difficulty == "late-python" %}
|
|
127
|
+
<div class="panel">
|
|
128
|
+
<div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
|
|
129
|
+
<p class="episode-title" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
130
|
+
{{episode.name}}
|
|
131
|
+
{% if episode.first_level != None and episode.last_level != None %}
|
|
132
|
+
{% if episode.first_level > 1009 %}
|
|
133
|
+
<span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
134
|
+
Levels {{episode.first_level|stringformat:"i"|slice:"2:4"}}-{{episode.last_level|stringformat:"i"|slice:"2:4"}}
|
|
135
|
+
</span>
|
|
136
|
+
{% else %}
|
|
137
|
+
{% if episode.last_level > 1009 %}
|
|
138
|
+
<span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
139
|
+
Levels {{episode.first_level|stringformat:"i"|slice:"3:4"}}-{{episode.last_level|stringformat:"i"|slice:"2:4"}}
|
|
140
|
+
</span>
|
|
141
|
+
{% else %}
|
|
142
|
+
<span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
|
|
143
|
+
Levels {{episode.first_level|stringformat:"i"|slice:"3:4"}}-{{episode.last_level|stringformat:"i"|slice:"3:4"}}
|
|
144
|
+
</span>
|
|
145
|
+
{% endif %}
|
|
146
|
+
{% endif %}
|
|
147
|
+
{% else %}
|
|
148
|
+
<span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes"></span>
|
|
149
|
+
{% endif %}
|
|
150
|
+
<img class="episode_image coin_image" value="{{episode.id}}">
|
|
151
|
+
</p>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
|
|
155
|
+
<div class="panel-body">
|
|
156
|
+
{% for level in episode.levels %}
|
|
157
|
+
{% for worksheet in episode.worksheets %}
|
|
158
|
+
{% if worksheet.before_level == level.id %}
|
|
159
|
+
{% if not user|is_logged_in or user.new_student.class_field in worksheet.locked_classes.all %}
|
|
160
|
+
{% if not user|is_logged_in %}
|
|
161
|
+
<p class="text--warning">In order to access the full content for this course, please log in.</p>
|
|
162
|
+
{% endif %}
|
|
163
|
+
<div class="col-sm-10 python-den-level">
|
|
164
|
+
<a class="disabled">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="col-sm-2 python-den-level">
|
|
167
|
+
<a class="button button--level button--icon disabled">
|
|
168
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
169
|
+
</div>
|
|
170
|
+
{% else %}
|
|
171
|
+
<div class="col-sm-7 python-den-level">
|
|
172
|
+
<a href="{% url 'worksheet' worksheet.id %}">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
|
|
173
|
+
</div>
|
|
174
|
+
{% if user|is_logged_in_as_teacher %}
|
|
175
|
+
<div class="col-sm-3 python-den-level">
|
|
176
|
+
<a href="{{worksheet.lesson_plan_link}}" class="button button--level button--icon" target="_blank">
|
|
177
|
+
Lesson plan<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="col-sm-2 python-den-level">
|
|
180
|
+
<a href="{{worksheet.slides_link}}" class="button button--level button--icon" target="_blank">
|
|
181
|
+
Slides<span class="iconify" data-icon="mdi:tray-arrow-down"></span></a>
|
|
182
|
+
</div>
|
|
183
|
+
{% elif user|is_independent_student %}
|
|
184
|
+
<div class="col-sm-3 python-den-level">
|
|
185
|
+
<a href="{{worksheet.indy_worksheet_link}}" class="button button--level button--icon" target="_blank">
|
|
186
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="col-sm-2 python-den-level">
|
|
189
|
+
<a href="{{worksheet.video_link}}" class="button button--level button--icon" target="_blank">
|
|
190
|
+
Video<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
191
|
+
</div>
|
|
192
|
+
{% else %}
|
|
193
|
+
<div class="col-sm-3"></div>
|
|
194
|
+
<div class="col-sm-2 python-den-level">
|
|
195
|
+
<a href="{{worksheet.student_worksheet_link}}" class="button button--level button--icon" target="_blank">
|
|
196
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
197
|
+
</div>
|
|
198
|
+
{% endif %}
|
|
199
|
+
{% endif %}
|
|
200
|
+
{% endif %}
|
|
201
|
+
{% endfor %}
|
|
202
|
+
{% if user|is_logged_in_as_student and user.new_student.class_field in level.locked_for_class.all %}
|
|
203
|
+
<!-- Mark level as locked -->
|
|
204
|
+
<p>
|
|
205
|
+
{% if level.name > 1009 %}
|
|
206
|
+
<a class="disabled">{{level.name|stringformat:"i"|slice:"2:4"}}: {{level.title.strip | safe}}</a>
|
|
207
|
+
{% else %}
|
|
208
|
+
<a class="disabled">{{level.name|stringformat:"i"|slice:"3:4"}}: {{level.title.strip | safe}}</a>
|
|
209
|
+
{% endif %}
|
|
210
|
+
{% if level.score != None %}
|
|
211
|
+
<span class="score_text disabled">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
|
|
212
|
+
<img class="level_image coin_image" value="{{level.name}}">
|
|
213
|
+
{% endif %}
|
|
214
|
+
</p>
|
|
215
|
+
{% elif not user.is_authenticated and level.name > 1026 and level.name != 1041 %}
|
|
216
|
+
<!-- Mark level as locked -->
|
|
217
|
+
<p>
|
|
218
|
+
{% if level.name > 1009 %}
|
|
219
|
+
<a class="disabled">{{level.name|stringformat:"i"|slice:"2:4"}}: {{level.title.strip | safe}}</a>
|
|
220
|
+
{% else %}
|
|
221
|
+
<a class="disabled">{{level.name|stringformat:"i"|slice:"3:4"}}: {{level.title.strip | safe}}</a>
|
|
222
|
+
{% endif %}
|
|
223
|
+
</p>
|
|
224
|
+
{% else %}
|
|
225
|
+
<!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
|
|
226
|
+
<p>
|
|
227
|
+
{% if level.name > 1009 %}
|
|
228
|
+
<a href="{% url 'play_python_default_level' level.name|stringformat:'i'|slice:'2:4' %}">{{level.name|stringformat:"i"|slice:"2:4"}}: {{level.title.strip | safe}}</a>
|
|
229
|
+
{% else %}
|
|
230
|
+
<a href="{% url 'play_python_default_level' level.name|stringformat:'i'|slice:'3:4' %}">{{level.name|stringformat:"i"|slice:"3:4"}}: {{level.title.strip | safe}}</a>
|
|
231
|
+
{% endif %}
|
|
232
|
+
{% if level.score != None %}
|
|
233
|
+
<span class="score_text">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
|
|
234
|
+
<img class="level_image coin_image" value="{{level.name}}">
|
|
235
|
+
{% endif %}
|
|
236
|
+
</p>
|
|
237
|
+
{% endif %}
|
|
238
|
+
{% endfor %}
|
|
239
|
+
{% for worksheet in episode.worksheets %}
|
|
240
|
+
{% if not worksheet.before_level %}
|
|
241
|
+
{% if not user|is_logged_in or user.new_student.class_field in worksheet.locked_classes.all %}
|
|
242
|
+
{% if not user|is_logged_in %}
|
|
243
|
+
<p class="text--warning">In order to access the full content for this course, please log in.</p>
|
|
244
|
+
{% endif %}
|
|
245
|
+
<div class="col-sm-10 python-den-level">
|
|
246
|
+
<a class="disabled">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
|
|
247
|
+
</div>
|
|
248
|
+
<div class="col-sm-2 python-den-level">
|
|
249
|
+
<a class="button button--level button--icon disabled">
|
|
250
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
251
|
+
</div>
|
|
252
|
+
{% else %}
|
|
253
|
+
<div class="col-sm-7 python-den-level">
|
|
254
|
+
<a href="{% url 'worksheet' worksheet.id %}">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
|
|
255
|
+
</div>
|
|
256
|
+
{% if user|is_logged_in_as_teacher %}
|
|
257
|
+
<div class="col-sm-3 python-den-level">
|
|
258
|
+
<a href="{{worksheet.lesson_plan_link}}" class="button button--level button--icon" target="_blank">
|
|
259
|
+
Lesson plan<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
260
|
+
</div>
|
|
261
|
+
<div class="col-sm-2 python-den-level">
|
|
262
|
+
<a href="{{worksheet.slides_link}}" class="button button--level button--icon" target="_blank">
|
|
263
|
+
Slides<span class="iconify" data-icon="mdi:tray-arrow-down"></span></a>
|
|
264
|
+
</div>
|
|
265
|
+
{% elif user|is_independent_student %}
|
|
266
|
+
<div class="col-sm-3 python-den-level">
|
|
267
|
+
<a href="{{worksheet.indy_worksheet_link}}" class="button button--level button--icon" target="_blank">
|
|
268
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
269
|
+
</div>
|
|
270
|
+
<div class="col-sm-2 python-den-level">
|
|
271
|
+
<a href="{{worksheet.video_link}}" class="button button--level button--icon" target="_blank">
|
|
272
|
+
Video<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
273
|
+
</div>
|
|
274
|
+
{% else %}
|
|
275
|
+
<div class="col-sm-3"></div>
|
|
276
|
+
<div class="col-sm-2 python-den-level">
|
|
277
|
+
<a href="{{worksheet.student_worksheet_link}}" class="button button--level button--icon" target="_blank">
|
|
278
|
+
Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
|
|
279
|
+
</div>
|
|
280
|
+
{% endif %}
|
|
281
|
+
{% endif %}
|
|
282
|
+
{% endif %}
|
|
283
|
+
{% endfor %}
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
{% endif %}
|
|
288
|
+
{% endfor %}
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
{% endblock content %}
|