Skip to content

Commit

Permalink
[UI IMPROVEMENT] Re-structured class customizations (hedyorg#1864)
Browse files Browse the repository at this point in the history
  • Loading branch information
TiBiBa authored Feb 4, 2022
1 parent 1c504d9 commit 880a511
Showing 16 changed files with 328 additions and 321 deletions.
15 changes: 10 additions & 5 deletions app.py
Original file line number Diff line number Diff line change
@@ -1106,24 +1106,29 @@ def index(level, step):
if 'adventure_name' in result:
adventure_name = result['adventure_name']

adventures, teacher_adventures, restrictions = DATABASE.get_student_restrictions(load_adventures_per_level(g.lang, level),
current_user()['username'], level)

adventures = load_adventures_per_level(g.lang, level)
customizations = {}
if current_user()['username']:
customizations = DATABASE.get_student_class_customizations(current_user()['username'])
level_defaults_for_lang = LEVEL_DEFAULTS[g.lang]

if level not in level_defaults_for_lang.levels or restrictions['hide_level']:
if level not in level_defaults_for_lang.levels or ('levels' in customizations and level not in customizations['levels']):
return utils.error_page(error=404, ui_message='no_such_level')
defaults = level_defaults_for_lang.get_defaults_for_level(level)
max_level = level_defaults_for_lang.max_level()

teacher_adventures = []
for adventure in customizations.get('teacher_adventures', []):
teacher_adventures.append(DATABASE.get_adventure(adventure))

return hedyweb.render_code_editor_with_tabs(
level_defaults=defaults,
max_level=max_level,
level_number=level,
version=version(),
adventures=adventures,
customizations=customizations,
teacher_adventures=teacher_adventures,
restrictions=restrictions,
loaded_program=loaded_program,
adventure_name=adventure_name)

12 changes: 12 additions & 0 deletions coursedata/pages/customize-class/en.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
explanation_1: |
Hi! On this page you can customize your class. By selecting levels and adventures you can choose what you student can see.
You can also add you own created adventures to levels. <b>Notice:</b> Not every adventure is available for every level!
Settings up your customizations goes as follows:
steps:
["Select levels for your class by pressing the \"level buttons\"", "\"Checkboxes\" will appear for the adventures available for the chosen levels",
"Select the adventures you want to make available", "Click the name of an adventure to (de)select for all levels",
"Add personal adventures", "Choose \"Save\" -> You're done!"]
explanation_2: |
You can always change these settings later on. For example, you can make specific adventures or levels available while teaching a class.
This way it's easy for you to determine which level and adventures your students will be working on.
If you want to make everything available for your class it is easiest to remove the customization all together.
11 changes: 11 additions & 0 deletions coursedata/pages/customize-class/nl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
explanation_1: |
Hoi! Hier kun je jouw klas personaliseren. Door het selecteren van levels en avonturen kun je kiezen wat jouw leerlingen kunnen zien.
Ook kun je jouw zelfgemaakte avonturen aan levels toevoegen. <b>Let op:</b> Niet elk avontuur is voor elk level beschikbaar! Het instellen gaat als volgt:
steps:
["Selecteer de levels voor jouw klas door op een \"level knop\" te drukken", "Er verschijnen \"selectievinkjes\" voor de beschikbare avonturen voor deze levels",
"Selecteer de avonturen die je beschikbaar wilt maken", "Klik op de naam van een avontuur om deze voor alle levels te (de)selecteren",
"Voeg eventueel persoonlijke avonturen toe", "Kies \"Opslaan\" -> je bent helemaal klaar!"]
explanation_2: |
Je kunt deze instellingen altijd op een later moment wijzigen. Zo kun je bijvoorbeeld tijdens het les geven nieuwe avonturen of levels beschikbaar maken.
Hierdoor is het voor leerlingen (en voor de leraar!) makkelijker om te kiezen waar aan gewerkt kan worden en wat er geleerd wordt.
Als je alles beschikbaar wilt maken voor jouw klas kun je het beste de "personalisatie" verwijderen, doe dit met de "verwijder" knop beneden in het scherm.
16 changes: 10 additions & 6 deletions coursedata/texts/en.yaml
Original file line number Diff line number Diff line change
@@ -307,16 +307,20 @@ Auth:
students: "students"
copy_class_link: "Copy link to join class"
join_prompt: "You need to have an account to join a class. Would you like to login now?"
available_adventures: "What adventures do you want to make available?"
other_settings: "Other settings"
example_programs: "Example programs?"
amount_next_level: "Amount needed next level"
hide_level: "Hide level?"
save: "Save"
reset: "Reset level"
programs: "Programs"
page: "page"
class_stats: "Show class statistics"
remove_customizations_prompt: "Are you sure you want to remove this class their customizations?"
class_customize_success: "Class successfully customized."
customization_deleted: "Customizations successfully deleted."
no_customizations: "There are not (yet) customizations for this class"
select_levels: "Select levels"
select_adventures: "Select adventures"
select_own_adventures: "Select own adventures"
reset_adventure_prompt: "Are you sure you want to reset all selected adventures?"
reset_adventures: "Reset selected adventures"
remove_customization: "Remove customization"
#Adventure customizations
customize_adventure: "Customize adventure"
general_settings: "General settings"
16 changes: 11 additions & 5 deletions coursedata/texts/nl.yaml
Original file line number Diff line number Diff line change
@@ -299,15 +299,21 @@ Auth:
students: "leerlingen"
copy_class_link: "Kopieer link om in te schrijven voor de klas"
join_prompt: "Je moet ingelogd zijn om je voor een klas in te kunnen schrijven. Wil je inloggen of een account maken?"
available_adventures: "Welke avonturen wil je beschikbaar maken?"
other_settings: "Overige instellingen"
example_programs: "Voorbeeld programma's?"
amount_next_level: "Aantal volgend level"
hide_level: "Level verbergen?"
save: "Opslaan"
reset: "Reset level"
programs: "Programma's"
page: "pagina"
class_stats: "Show class statistics"
remove_customizations_prompt: "Weet je zeker dat je de personalisatie van deze klas wilt verwijderen?"
class_customize_success: "Klas succesvol gepersonaliseerd."
customization_deleted: "Personalisatie succesvol verwijderd."
no_customizations: "Er is (nog) geen personalisatie voor deze klas"
select_levels: "Levels selecteren"
select_adventures: "Avonturen selecteren"
select_own_adventures: "Eigen avonturen selecteren"
reset_adventure_prompt: "Weet je zeker dat je alle geselecteerde avonturen wilt wissen?"
reset_adventures: "Wis gekozen avonturen"
remove_customization: "Verwijder Personalisatie"
#Adventure customizations
customize_adventure: "Avontuur aanpassen"
general_settings: "Algemene instellingen"
8 changes: 3 additions & 5 deletions hedyweb.py
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ def get_page_title(current_page):
return page_titles_json['start'].get("en")


def render_code_editor_with_tabs(level_defaults, max_level, level_number, version, loaded_program, adventures, teacher_adventures, restrictions, adventure_name):
def render_code_editor_with_tabs(level_defaults, max_level, level_number, version, loaded_program, adventures, customizations, teacher_adventures, adventure_name):
user = current_user()

if not level_defaults:
@@ -90,9 +90,8 @@ def render_code_editor_with_tabs(level_defaults, max_level, level_number, versio
arguments_dict['level'] = level_number
arguments_dict['prev_level'] = int(level_number) - 1 if int(level_number) > 1 else None
arguments_dict['next_level'] = int(level_number) + 1 if int(level_number) < max_level else None
arguments_dict['example_programs'] = restrictions['example_programs']
arguments_dict['hide_prev_level'] = restrictions['hide_prev_level']
arguments_dict['hide_next_level'] = restrictions['hide_next_level']
arguments_dict['customizations'] = customizations
arguments_dict['teacher_adventures'] = teacher_adventures
arguments_dict['menu'] = True
arguments_dict['latest'] = version
arguments_dict['selected_page'] = 'code'
@@ -101,7 +100,6 @@ def render_code_editor_with_tabs(level_defaults, max_level, level_number, versio
arguments_dict['is_teacher'] = is_teacher(user)
arguments_dict['loaded_program'] = loaded_program
arguments_dict['adventures'] = adventures
arguments_dict['teacher_adventures'] = teacher_adventures
arguments_dict['adventure_name'] = adventure_name

# Merge level defaults into adventures so it is rendered as the first tab
2 changes: 1 addition & 1 deletion static/css/generated.css

Large diffs are not rendered by default.

23 changes: 0 additions & 23 deletions static/js/appbundle.js

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions static/js/appbundle.js.map

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion static/js/tabs.ts
Original file line number Diff line number Diff line change
@@ -60,7 +60,8 @@ $(function() {
// - Store the teacher_adventure code in the state -> similar to "normal" adventures
// - We load on the correct tab
$ ('#program_name').val (tabName);
window.State.adventure_name = tabName
window.State.adventure_name = tabName;
window.State.unsaved_changes = false;
theGlobalEditor?.setValue ("");
return;
}
150 changes: 100 additions & 50 deletions static/js/teachers.ts
Original file line number Diff line number Diff line change
@@ -321,60 +321,110 @@ export function show_doc_section(section_key: string) {
}
}

export function save_level_settings(id: string, level: number) {
let selected_adventures: (string | null)[] = [];
$('#adventures_overview li').each(function() {
if ($(this).is(':visible') && $(this).find(':input').prop('checked')) {
selected_adventures.push(this.getAttribute('id'));
}
});
//https://stackoverflow.com/questions/7196212/how-to-create-dictionary-and-add-key-value-pairs-dynamically?rq=1
export function save_customizations(class_id: string) {
let levels: (string | undefined)[] = [];
$('.level-select-button').each(function() {
if ($(this).hasClass("green-btn")) {
levels.push(<string>$(this).val());
}
});
let adventures = {};
$('.adventure_keys').each(function() {
const name = <string>$(this).attr('adventure');
// @ts-ignore
adventures[name] = [];
});
$('.adventure_level_input').each(function() {
const name = <string>$(this).attr('adventure');
// @ts-ignore
let current_list = adventures[name];
if ($(this).prop("checked")) {
current_list.push(<string>$(this).attr('level'));
// @ts-ignore
adventures[name] = current_list;
}
});
let teacher_adventures: string[] = [];
$('.teacher_adventures_checkbox').each(function() {
if ($(this).prop("checked")) {
teacher_adventures.push(<string>$(this).attr('id'));
}
});

let selected_teacher_adventures: (string | null)[] = [];
$('#teacher_adventures_overview li').each(function() {
if ($(this).is(':visible') && $(this).find(':input').prop('checked')) {
selected_teacher_adventures.push(this.getAttribute('id'));
}
});
$.ajax({
type: 'POST',
url: '/for-teachers/customize-class/' + class_id,
data: JSON.stringify({
levels: levels,
adventures: adventures,
teacher_adventures: teacher_adventures
}),
contentType: 'application/json',
dataType: 'json'
}).done(function (response) {
modal.alert(response.success, 3000, false);
$('#remove_customizations_button').removeClass('hidden');
$('#customizations_alert').addClass('hidden');
}).fail(function (err) {
modal.alert(err.responseText, 3000, true);
});
}

const hide_level = !!$(`#hide_level${level}`).prop('checked');
const hide_next_level = !!$(`#hide_level${level - 1}`).prop('checked');
const example_programs = !!$(`#example_programs${level}`).prop('checked');
const hide_prev_level = !!$(`#hide_level${level - 1}`).prop('checked');
export function remove_customizations(class_id: string) {
modal.confirm (auth.texts['remove_customizations_prompt'], function () {
$.ajax({
type: 'DELETE',
url: '/for-teachers/customize-class/' + class_id,
contentType: 'application/json',
dataType: 'json'
}).done(function (response) {
modal.alert(response.success, 3000, false);
$('#remove_customizations_button').addClass('hidden');
$('#customizations_alert').removeClass('hidden');
$('.adventure_level_input').prop('checked', false);
$('.teacher_adventures_checkbox').prop('checked', false);
$('.level-select-button').removeClass('green-btn');
$('.level-select-button').addClass('blue-btn');
}).fail(function (err) {
modal.alert(err.responseText, 3000, true);
});
});
}

$.ajax({
type: 'PUT',
url: '/customize-class/' + id,
data: JSON.stringify({
adventures: selected_adventures,
teacher_adventures: selected_teacher_adventures,
example_programs: example_programs,
hide_level: hide_level,
hide_prev_level: hide_prev_level,
hide_next_level: hide_next_level,
level: level
}),
contentType: 'application/json',
dataType: 'json'
}).done(function(response) {
if (response.achievement) {
showAchievements(response.achievement, true, "");
} else {
// location.reload ();
// TODO TB -> Front-end already up to date; no need for re-load! Look into this with customizations impro.
}
}).fail(function(err) {
console.error(err);
error.show(ErrorMessages['Connection_error'], JSON.stringify(err));
});
export function select_all_levels_adventure(adventure_name: string) {
let first_input = true;
let checked = true;
$('.adventure_level_input').each(function() {
const name = <string>$(this).attr('adventure');
if (name == adventure_name && $(this).is(":visible")) {
if (first_input) {
checked = $(this).prop("checked");
first_input = false;
}
$(this).prop("checked", !checked);
}
});
}

export function reset_level_preferences(level: number) {
$('#adventures_overview li').each(function() {
if ($(this).is(':visible')) {
$(this).find(':input').prop("checked", true);
}
});
$('#example_programs' + level).prop("checked", true);
$('#hide_level' + level).prop("checked", false);
export function select_all_level_adventures(level: string) {
// It is not selected yet -> select all and change color
if ($('#level_button_' + level).hasClass('blue-btn')) {
$('.adventure_level_' + level).each(function(){
$(this).removeClass('hidden');
if ($(this).is(':enabled')) {
$(this).prop("checked", true);
}
});
$('#level_button_' + level).removeClass('blue-btn');
$('#level_button_' + level).addClass('green-btn');
} else {
$('.adventure_level_' + level).each(function () {
$(this).prop("checked", false);
$(this).addClass('hidden');
});
$('#level_button_' + level).removeClass('green-btn');
$('#level_button_' + level).addClass('blue-btn');
}
}

Loading

0 comments on commit 880a511

Please sign in to comment.