Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Prep final clean" #35221

Merged
merged 1 commit into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
56 changes: 55 additions & 1 deletion dashboard/app/views/levels/editors/_artist.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,58 @@
- level_type = ['anna', 'elsa'].include?(@level.skin) ? 'frozen' : 'artist'
= render partial: 'levels/editors/fields/encrypted_examples', locals: {f: f, level_type: level_type}

= render partial: 'levels/editors/fields/artist_editors', locals: {f: f}
%h1.control-legend{data: {toggle: "collapse", target: "#artist"}}
Artist Settings

#artist.in.collapse
.field
= f.label :slider_speed, 'Slider speed (artist only)'
%p Number from 0.0 to 1.0 for how fast artist runs. If not set, default is 1.0
= f.number_field :slider_speed, :step => 0.1
.field
= render partial: 'levels/editors/fields/checkboxes', locals: {f: f, field_name: :impressive, description: "Impressive"}
%p Impressive levels can be shared and are automatically saved to the private gallery
.field
= render partial: 'levels/editors/fields/checkboxes', locals: {f: f, field_name: :discard_background, description: "Discard Background"}
%p If a level has a background image, don't display that image as feedback or include it in the image saved to the private gallery
.field
= f.label :start_direction, 'Start Direction (in degrees)'
= f.number_field :start_direction, :in => 0...360, :value => @level.start_direction
.field
= f.label :x
= f.number_field :x, :value => @level.x
.field
= f.label :y
= f.number_field :y, :value => @level.y
.field
= f.label :permitted_errors, 'Permitted errors (default 0)'
= f.number_field :permitted_errors, :value => @level.permitted_errors
.field
= f.label :auto_run, 'Automatically rerun on block changes'
:ruby
selector = f.select :auto_run, options_for_select([
['No', nil],
['Yes', SharedConstants::ARTIST_AUTORUN_OPTIONS.full_auto_run],
], selected: @level.auto_run)
= selector
.field
= link_to 'Edit Predraw Blocks', edit_blocks_level_path(@level, :predraw_blocks) unless @level.new_record?
= render partial: 'levels/editors/fields/collapsible_block_editor', locals: {f: f, xml_id: 'predraw'}
:javascript
levelbuilder.initializeCodeMirror('level_predraw_blocks', '#{@level.uses_droplet? ? 'javascript' : 'xml'}');
.field
= f.label :images, 'Image field in JSON array format, e.g.:'
%div
%pre{:style => '-webkit-user-select: text'}
= preserve do
:escaped
[
{"filename": "https://images.code.org/cat.png", "position": [16, 170]},
{"filename": "https://images.code.org/lion.png", "position": [15, 250]},
{"filename": "https://images.code.org/elephant.png", "position": [127, 220]},
{"filename": "https://images.code.org/cow.png", "position": [255, 250]}
]
%p Paste or drag images into this field to upload them, similar to adding images to Long Instructions.
= f.text_area :images, placeholder: 'Images', rows: 4, value: @level.properties['images']
:javascript
levelbuilder.initializeCodeMirror('level_images', 'javascript', {attachments: true});
18 changes: 17 additions & 1 deletion dashboard/app/views/levels/editors/_bounce.html.haml
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
= render partial: 'levels/editors/fields/control_buttons', locals: {f: f}
= render partial: 'levels/editors/fields/bounce_editors', locals: {f: f}

%h1.control-legend{data: {toggle: "collapse", target: "#bounce"}}
Bounce Settings

#bounce.in.collapse
= render partial: 'levels/editors/fields/checkboxes', locals: {f: f, field_name: 'use_flag_goal', description: "Use Flag Goal"}
= render partial: 'levels/editors/fields/checkboxes', locals: {f: f, field_name: 'fail_on_ball_exit', description: "Fail on Ball Exit"}
.field
= f.label :theme, 'Theme'
%p
NOTE that not all themes are compatible with all skins. Specifically, the
bounce and basketball skins can only have retro or basketball themes, while
the sports skin can have any theme except retro.
= f.select :theme, options_for_select(Bounce.themes, @level.theme)
.field
= f.label :ball_direction, 'Ball Direction (in radians)'
= f.number_field :ball_direction, step: :any
218 changes: 217 additions & 1 deletion dashboard/app/views/levels/editors/_craft.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,220 @@
- content_for(:head) do
%script{src: webpack_asset_path('js/levels/editors/_craft.js')}

= render partial: 'levels/editors/fields/craft_editors', locals: {f: f}
%h1.control-legend{data: {toggle: "collapse", target: "#minecraft"}}
Minecraft Settings

#minecraft.in.collapse

.field
= f.label :player_start_position, 'Player Start Position in format [x, y]'
= f.text_field :player_start_position
.field
= f.label :player_start_direction, 'Player Start Direction'
= f.select :player_start_direction, options_for_select(@level.class.start_directions, @level.player_start_direction)
.field
= f.label :is_daytime, 'Start level daytime'
= boolean_check_box(f, :is_daytime)
.field
= f.label :is_event_level, 'Is an "Events" (HoC 2016) level'
= boolean_check_box(f, :is_event_level)
.field
= f.label :is_agent_level, 'Is an "Agent" (HoC 2017) level'
= boolean_check_box(f, :is_agent_level)
.field
= f.label :is_aquatic_level, 'Is an "Aquatic" (HoC 2018) level'
= boolean_check_box(f, :is_aquatic_level)
.field
= f.label :boat, 'Start player in the rowboat (Aquatic levels only, player must be positioned over water)'
= boolean_check_box(f, :boat)
.field
= f.label :ocean, 'Underwater overlay type'
= f.select :ocean, options_for_select([['None', nil], ['Warm Ocean', 'warm'], ['Cold Ocean', 'cold']], @level.ocean)
.field
= f.label :agent_start_position, 'Agent Start Position in format [x, y]'
= f.text_field :agent_start_position
.field
= f.label :agent_start_direction, 'Agent Start Direction'
= f.select :agent_start_direction, options_for_select(@level.class.start_directions, @level.agent_start_direction)
.field
= f.label :use_player, 'Show player in level'
= boolean_check_box(f, :use_player)
.field
= f.label :use_score, 'Show a score in the level'
= boolean_check_box(f, :use_score)
.field
= f.label :day_night_cycle_time, 'Day/night cycle length in seconds (0 is no cycle)'
= f.text_field :day_night_cycle_time, {value: @level.day_night_cycle_time || 0}
.field
= f.label :day_night_cycle_start, 'Time until first day/night cycle starts (in seconds)'
= f.text_field :day_night_cycle_start, {value: @level.day_night_cycle_start || 0}
.field
= f.label :show_popup_on_load, 'Show Popup on Level Start'
= f.select :show_popup_on_load, options_for_select(@level.class.show_popup_options, @level.show_popup_on_load), {include_blank: true}
.field
= f.label :special_level_type, 'Special level type'
= f.select :special_level_type, options_for_select(@level.class.special_level_type_options, @level.special_level_type), {include_blank: true}
.field
= f.label :verification_function, 'Verification Function'
Click to insert: (
- Craft::SAMPLE_VERIFICATION_FUNCTIONS.each do |name, value|
:javascript
var verificationFunction#{name} = '#{value.gsub('\n', "\\n' + '")}';
%a{style:"cursor: pointer", onclick: "verificationEditor.getDoc().setValue(verificationFunction#{name})"}= name
)
= f.text_area :verification_function, rows: 10
:javascript
var verificationEditor = levelbuilder.initializeCodeMirror('level_verification_function', 'javascript');
.field
= f.label :timeout_verification_function, 'Timeout Verification Function (check success/fail after a timeout hit)'
Click to insert: (
- Craft::SAMPLE_TIMEOUT_VERIFICATION_FUNCTIONS.each do |name, value|
:javascript
var verificationFunction#{name} = '#{value.gsub('\n', "\\n' + '")}';
%a{style:"cursor: pointer", onclick: "verificationEditorTimeout.getDoc().setValue(verificationFunction#{name})"}= name
)
= f.text_area :timeout_verification_function, rows: 10
:javascript
var verificationEditorTimeout = levelbuilder.initializeCodeMirror('level_timeout_verification_function', 'javascript');
.field
= f.label :failure_check_function, 'Should fail early function'
Click to insert: (
- Craft::SAMPLE_EARLY_FAILURE_CHECK_FUNCTIONS.each do |name, value|
:javascript
var earlyFailureFunction#{name} = '#{value.gsub('\n', "\\n' + '")}';
%a{style:"cursor: pointer", onclick: "earlyFailureEditor.getDoc().setValue(earlyFailureFunction#{name})"}= name
)
= f.text_area :failure_check_function, rows: 10
:javascript
var earlyFailureEditor = levelbuilder.initializeCodeMirror('level_failure_check_function', 'javascript');
.field
= f.label :level_verification_timeout, 'Level verification timeout in milliseconds (failure if player does not succeed in allotted time)'
= f.text_field :level_verification_timeout, {value: @level.level_verification_timeout || 0}

.field
= f.label :drop_dropdown_options, 'Available drop dropdown items'
- drop_dropdown_options = @level.drop_dropdown_options.is_a?(String) ? JSON.parse(@level.drop_dropdown_options) : @level.drop_dropdown_options
= f.select :drop_dropdown_options, options_for_select(Craft::ALL_MINIBLOCKS.keys, drop_dropdown_options), {}, {multiple: true, class: "selectize"}

.field
= f.label :play_sound_options, 'Available play sound sounds'
- play_sound_options = @level.play_sound_options.is_a?(String) ? JSON.parse(@level.play_sound_options) : @level.play_sound_options
= f.select :play_sound_options, options_for_select(Craft::ALL_SOUNDS.keys, play_sound_options), {}, {multiple: true, class: "selectize"}

.field
= f.label :available_blocks, 'Available Blocks'
- available_blocks = @level.available_blocks.is_a?(String) ? JSON.parse(@level.available_blocks) : @level.available_blocks
= f.select :available_blocks, options_for_select(Craft::ALL_BLOCKS.keys, available_blocks), {}, {multiple: true, class: "selectize"}

.field
= f.label :if_block_options, 'Override if and while ahead block dropdown options'
- if_block_options = @level.if_block_options.is_a?(String) ? JSON.parse(@level.if_block_options) : @level.if_block_options
= f.select :if_block_options, options_for_select(Craft::ALL_BLOCKS.keys, if_block_options), {}, {multiple: true, class: "selectize"}

.field
= f.label :place_block_options, 'Override place and place ahead block dropdown options'
- place_block_options = @level.place_block_options.is_a?(String) ? JSON.parse(@level.place_block_options) : @level.place_block_options
= f.select :place_block_options, options_for_select(Craft::ALL_BLOCKS.keys, place_block_options), {}, {multiple: true, class: "selectize"}

.field
= f.label :songs, 'Background Music. Format: ["first song to play", "second song to play", ...]'
%a{style:"cursor: pointer", onclick: "songsEditor.getDoc().setValue('#{Craft.song_options}')"}= "Insert all"
= f.text_area :songs, rows: 10
:javascript
var songsEditor = levelbuilder.initializeCodeMirror('level_songs', 'javascript');

%div{style: "opacity: .5"}
.field
= f.label :grid_width, 'Grid width (warning: do not change, only use for initial sizing)'
= f.text_field :grid_width, {value: @level.get_width}
.field
= f.label :grid_height, 'Grid height (warning: do not change, only use for initial sizing)'
= f.text_field :grid_height, {value: @level.get_height}

- Craft::JSON_LEVEL_MAPS.each do |level_json_name|
.field
= f.hidden_field level_json_name
= f.label "Map for #{level_json_name}"
.map-editor-table{:id => "map-table-#{level_json_name}"}

:css
tr {
min-height: 100px;
min-width: 100px;
}

td {
background-repeat: no-repeat;
background-position: 50px;
}

- Craft::TILES_TO_PREVIEW_IMAGES.each do |tile, preview|
:css
td.#{tile} {
background-image: url('#{preview}');
}

:javascript
function padFlatArrayToWidthHeight(array, width, height) {
var extraNeeded = width * height - array.length;
for (var i = 0; i < extraNeeded; i++) {
array.push('grass');
}

array.length = width * height; // truncate

return array;
}
function arrayTo2d(array, width) {
var arrayCopy = array.slice(0);
var array2d = [];
while (arrayCopy.length > 0) {
array2d.push(arrayCopy.splice(0, width));
}
return array2d;
}

function array2dToFlat(array2d) {
return [].concat.apply([], array2d);
}

function tableFor(map_property_name, data, possibleValues) {
var array2d = arrayTo2d(padFlatArrayToWidthHeight(data, #{@level.get_width}, #{@level.get_height}), #{@level.get_width});

var mapDivID = "#map-table-" + map_property_name;
var allColumns = [];
var allColumnWidths = [];
var columnConfig = {
type: 'autocomplete',
source: possibleValues,
strict: false
};
for(var i = 0; i < #{@level.get_width}; i++) {
allColumns.push(columnConfig);
allColumnWidths.push(100);
}
$(mapDivID).handsontable({
data: array2d,
startRows: #{@level.get_height},
startCols: #{@level.get_width},
maxRows: #{@level.get_height},
maxCols: #{@level.get_width},
columns: allColumns,
colWidths: allColumnWidths,
stretchH: 'none',
afterChange: function(changes, source) {
$("#level_" + map_property_name).val(JSON.stringify(array2dToFlat(array2d)));
},
cells: function(row, col, prop) {
return {renderer: renderMaze};
}});
}

function renderMaze(instance, td, row, col, prop, value, cellProperties) {
td.className += ' ' + value;
Handsontable.renderers.AutocompleteRenderer.apply(this, arguments);
}

- Craft::JSON_LEVEL_MAPS.each do |level_json_name|
:javascript
tableFor("#{level_json_name}", eval(#{@level.properties[level_json_name.to_s]}), #{Craft::KNOWN_TILE_TYPES[level_json_name].keys.map{|key| key.to_s}});
7 changes: 6 additions & 1 deletion dashboard/app/views/levels/editors/_dance.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
= render partial: 'levels/editors/fields/default_song', locals: {f: f}
%h1.control-legend{data: {toggle: "collapse", target: "#defaultSong"}}
Default Song

#defaultSong.in.collapse
= f.label :default_song, 'Default Song'
= f.select :default_song, options_for_select(@level.class.hoc_songs, @level.default_song)

= render partial: 'levels/editors/fields/debugger', locals: {f: f}

Expand Down
54 changes: 53 additions & 1 deletion dashboard/app/views/levels/editors/_dsl.html.haml
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@
= render partial: 'levels/editors/fields/dsl_editors', locals: {f: f}
:scss
$cyan: #0094ca;
$light_cyan: #59b9dc;
$lighter_cyan: #a6daed;
$lightest_cyan: #d9eff7;

.script_text textarea { width: 100%; height: 100px}
.markdown {
border: 5px solid gray;
border-radius: 5px;
padding: 10px;
}

.field.teacher-only-markdown {
border: 5px solid gray;
border-radius: 5px;
padding: 10px;
}

#level_teacher_markdown_textarea_preview {
border: 5px solid $cyan;
background-color: $lightest_cyan;
padding: 10px;
}

%h1.control-legend{data: {toggle: "collapse", target: "#dsl_editor"}}
DSL Editor

#dsl_editor.in.collapse
.script_text
= text_area_tag('level[dsl_text]', @level.dsl_text || (@level.dsl_default))

- if @level.supports_markdown?
- content_for(:head) do
%script{src: webpack_asset_path('js/levels/editors/_dsl.js')}

.markdown
%p Edit Markdown:

%textarea#level_markdown_textarea
#level_markdown_textarea_preview

// Don't not use the _teacher_only_markdown.haml partial for DSL levels because they need
// extra functionality (initializeEmbeddedMarkdownEditor) to save the markdown content into the level file
- unless @level.is_a?(EvaluationMulti)
%h1.control-legend{data: {toggle: "collapse", target: "#teacher_only_markdown"}}
Teacher Only Markdown

#teacher_only_markdown.in.collapse
.field.teacher-only-markdown

%textarea#level_teacher_markdown_textarea
#level_teacher_markdown_textarea_preview
12 changes: 11 additions & 1 deletion dashboard/app/views/levels/editors/_external_link.html.haml
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
= render partial: 'levels/editors/fields/external_link_editors', locals: {f: f}
%h1.control-legend{data: {toggle: "collapse", target: "#link-settings"}}
Link Settings

#link-settings.in.collapse
.field
= f.label :url
= f.text_field :url, {style: 'width: 100%'}
.field
= f.label :link_title
= f.text_field :link_title, {style: 'width: 100%'}