Rework left sidebar
* Move Buttons from left sidebar to JSTree * Use light style for collapse sidebar buttons
This commit is contained in:
@ -198,7 +198,7 @@ var CodeOceanEditor = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
hideSpinner: function () {
|
hideSpinner: function () {
|
||||||
$('button i.fa').show();
|
$('button i.fa, button i.far, button i.fas').show();
|
||||||
$('button i.fa-spin').hide();
|
$('button i.fa-spin').hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ var CodeOceanEditor = {
|
|||||||
|
|
||||||
resizeParentOfAceEditor: function (element) {
|
resizeParentOfAceEditor: function (element) {
|
||||||
// calculate needed size: window height - position of top of ACE editor - height of autosave label below editor - 5 for bar margins
|
// calculate needed size: window height - position of top of ACE editor - height of autosave label below editor - 5 for bar margins
|
||||||
var windowHeight = window.innerHeight - $(element).offset().top - $('#autosave-label').height() - 5;
|
var windowHeight = window.innerHeight - $(element).offset().top - $('#statusbar').height() - 5;
|
||||||
$(element).parent().height(windowHeight);
|
$(element).parent().height(windowHeight);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ var CodeOceanEditor = {
|
|||||||
document.insertLines(0, content.text().split(/\n/));
|
document.insertLines(0, content.text().split(/\n/));
|
||||||
// remove last (empty) that is there by default line
|
// remove last (empty) that is there by default line
|
||||||
document.removeLines(document.getLength() - 1, document.getLength() - 1);
|
document.removeLines(document.getLength() - 1, document.getLength() - 1);
|
||||||
editor.setReadOnly($(element).data('read-only') !== undefined);
|
editor.setReadOnly($(element).parent().data('read-only') !== undefined);
|
||||||
if (editor.getReadOnly()) {
|
if (editor.getReadOnly()) {
|
||||||
editor.setHighlightActiveLine(false);
|
editor.setHighlightActiveLine(false);
|
||||||
editor.setHighlightGutterLine(false);
|
editor.setHighlightGutterLine(false);
|
||||||
@ -341,11 +341,9 @@ var CodeOceanEditor = {
|
|||||||
|
|
||||||
initializeFileTreeButtons: function () {
|
initializeFileTreeButtons: function () {
|
||||||
$('#create-file').on('click', this.showFileDialog.bind(this));
|
$('#create-file').on('click', this.showFileDialog.bind(this));
|
||||||
$('#create-file-collapsed').on('click', this.showFileDialog.bind(this));
|
|
||||||
$('#destroy-file').on('click', this.confirmDestroy.bind(this));
|
$('#destroy-file').on('click', this.confirmDestroy.bind(this));
|
||||||
$('#destroy-file-collapsed').on('click', this.confirmDestroy.bind(this));
|
$('#destroy-file-collapsed').on('click', this.confirmDestroy.bind(this));
|
||||||
$('#download').on('click', this.downloadCode.bind(this));
|
$('#download').on('click', this.downloadCode.bind(this));
|
||||||
$('#download-collapsed').on('click', this.downloadCode.bind(this));
|
|
||||||
$('#request-for-comments').on('click', this.requestComments.bind(this));
|
$('#request-for-comments').on('click', this.requestComments.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -580,7 +578,7 @@ var CodeOceanEditor = {
|
|||||||
|
|
||||||
toggleButtonStates: function () {
|
toggleButtonStates: function () {
|
||||||
$('#destroy-file').prop('disabled', this.active_frame.data('role') !== 'user_defined_file');
|
$('#destroy-file').prop('disabled', this.active_frame.data('role') !== 'user_defined_file');
|
||||||
$('#start-over-active-file').prop('disabled', this.active_frame.data('role') === 'user_defined_file');
|
$('#start-over-active-file').prop('disabled', this.active_frame.data('role') === 'user_defined_file' || this.active_frame.data('read-only') !== undefined);
|
||||||
$('#dummy').toggle(!this.fileActionsAvailable());
|
$('#dummy').toggle(!this.fileActionsAvailable());
|
||||||
$('#render').toggle(this.isActiveFileRenderable());
|
$('#render').toggle(this.isActiveFileRenderable());
|
||||||
$('#run').toggle(this.isActiveFileRunnable() && !this.running);
|
$('#run').toggle(this.isActiveFileRunnable() && !this.running);
|
||||||
@ -654,7 +652,7 @@ var CodeOceanEditor = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
showSpinner: function (initiator) {
|
showSpinner: function (initiator) {
|
||||||
$(initiator).find('i.fa').hide();
|
$(initiator).find('i.fa, i.far, i.fas').hide();
|
||||||
$(initiator).find('i.fa-spin').show();
|
$(initiator).find('i.fa-spin').show();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ CodeOceanEditorSubmissions = {
|
|||||||
|
|
||||||
AUTOSAVE_INTERVAL: 15 * 1000,
|
AUTOSAVE_INTERVAL: 15 * 1000,
|
||||||
autosaveTimer: null,
|
autosaveTimer: null,
|
||||||
autosaveLabel: "#autosave-label span",
|
autosaveLabel: "#statusbar span",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submission-Creation
|
* Submission-Creation
|
||||||
|
@ -12,7 +12,7 @@ h1, h2, h3, h4, h5, h6 {
|
|||||||
color: rgba(70, 70, 70, 1);
|
color: rgba(70, 70, 70, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
i.fa {
|
i.fa, i.far, i.fas {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,10 +85,10 @@ button i.fa-spin {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#autosave-label{
|
#statusbar{
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
margin-top: .2em;
|
||||||
height: 1.6em;
|
height: 1.6em;
|
||||||
text-align: right;
|
|
||||||
color: #777;
|
color: #777;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ module CodeOcean
|
|||||||
@file.content = content
|
@file.content = content
|
||||||
end
|
end
|
||||||
authorize!
|
authorize!
|
||||||
create_and_respond(object: @file, path: proc { implement_exercise_path(@file.context.exercise, tab: 2) })
|
create_and_respond(object: @file, path: proc { implement_exercise_path(@file.context.exercise) })
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_and_respond(options = {})
|
def create_and_respond(options = {})
|
||||||
|
@ -24,13 +24,29 @@
|
|||||||
= render('editor_button', data: {:'data-placement' => 'top', :'data-toggle' => 'tooltip', :'data-container' => 'body'}, icon: 'fa fa-trophy', id: 'assess', label: t('exercises.editor.score'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + s')) unless @embed_options[:disable_score]
|
= render('editor_button', data: {:'data-placement' => 'top', :'data-toggle' => 'tooltip', :'data-container' => 'body'}, icon: 'fa fa-trophy', id: 'assess', label: t('exercises.editor.score'), title: t('shared.tooltips.shortcut', shortcut: 'ALT + s')) unless @embed_options[:disable_score]
|
||||||
- unless hide_rfc_button
|
- unless hide_rfc_button
|
||||||
= render('editor_button', icon: 'fa fa-comment', id: 'requestComments', label: t('exercises.editor.requestComments'), title: t('exercises.editor.requestCommentsTooltip'))
|
= render('editor_button', icon: 'fa fa-comment', id: 'requestComments', label: t('exercises.editor.requestComments'), title: t('exercises.editor.requestCommentsTooltip'))
|
||||||
|
|
||||||
- @files.each do |file|
|
- @files.each do |file|
|
||||||
- file.read_only = true if @embed_options[:read_only]
|
- file.read_only = true if @embed_options[:read_only]
|
||||||
= render('editor_frame', exercise: exercise, file: file)
|
= render('editor_frame', exercise: exercise, file: file)
|
||||||
#autosave-label
|
|
||||||
= t('exercises.editor.lastsaved')
|
#statusbar.d-flex.justify-content-between
|
||||||
span
|
div
|
||||||
button style="display:none" id="autosave"
|
- if !@embed_options[:disable_download] && @exercise.hide_file_tree?
|
||||||
|
button#download.p-0.border-0.btn-link.visible.bg-white
|
||||||
|
i.fas.fa-arrow-down
|
||||||
|
= t('exercises.editor.download')
|
||||||
|
|
||||||
|
div
|
||||||
|
= t('exercises.editor.lastsaved')
|
||||||
|
span
|
||||||
|
button style="display:none" id="autosave"
|
||||||
|
|
||||||
|
= " | "
|
||||||
|
|
||||||
|
button#start-over-active-file.p-0.border-0.btn-link.bg-white data-message-confirm=t('exercises.editor.confirm_start_over_active_file') data-url=reload_exercise_path(@exercise)
|
||||||
|
i.fa.fa-history
|
||||||
|
= t('exercises.editor.start_over_active_file')
|
||||||
|
|
||||||
- unless @embed_options[:disable_run] && @embed_options[:disable_score]
|
- unless @embed_options[:disable_run] && @embed_options[:disable_score]
|
||||||
div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id )
|
div id='output_sidebar' class='output-col-collapsed' = render('exercises/editor_output', external_user_id: external_user_id, consumer_id: consumer_id )
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
button.btn class=local_assigns.fetch(:classes, 'btn-primary') *local_assigns.fetch(:data, {}) disabled=local_assigns.fetch(:disabled, false) id=id title=local_assigns[:title] type='button'
|
button.btn class=local_assigns.fetch(:classes, 'btn-primary') *local_assigns.fetch(:data, {}) disabled=local_assigns.fetch(:disabled, false) id=id title=local_assigns[:title] type='button'
|
||||||
i.fa.fa-circle-o-notch.fa-spin
|
i.fa.fa-circle-o-notch.fa-spin class=(label.blank? ? "m-0" : '')
|
||||||
i class=(label.present? ? icon : "#{icon} m-0")
|
i class=(label.present? ? icon : "#{icon} m-0")
|
||||||
= label
|
= label
|
||||||
|
@ -1,44 +1,42 @@
|
|||||||
div id='sidebar-collapsed' class=(@exercise.hide_file_tree && @tips.blank? ? '' : 'd-none')
|
div id='sidebar-collapsed' class=(@exercise.hide_file_tree && @tips.blank? ? '' : 'd-none')
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-plus-square', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar'))
|
= render('editor_button', classes: 'btn-block btn-outline-dark btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-plus-square', id: 'sidebar-collapse-collapsed', label:'', title:t('exercises.editor.expand_action_sidebar'))
|
||||||
|
|
||||||
- if @exercise.allow_file_creation and not @exercise.hide_file_tree?
|
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-cause' => 'file', :'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-plus', id: 'create-file-collapsed', label:'', title: t('exercises.editor.create_file'))
|
|
||||||
|
|
||||||
- unless @embed_options[:disable_hints] or @tips.blank?
|
- unless @embed_options[:disable_hints] or @tips.blank?
|
||||||
= render('editor_button', classes: 'btn-block btn-secondary btn mb-4', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-lightbulb', id: 'tips-collapsed', label:'', title: t('exercises.form.tips'))
|
= render('editor_button', classes: 'btn-block btn-secondary btn mb-4', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-lightbulb', id: 'tips-collapsed', label:'', title: t('exercises.form.tips'))
|
||||||
|
|
||||||
- unless @embed_options[:disable_download]
|
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-download', id: 'download-collapsed', label:'', title: t('exercises.editor.download'))
|
|
||||||
= render('editor_button', classes: "btn-block btn-outline-warning btn enforce-top-margin #{@exercise.hide_file_tree || files.count < 2 && !@exercise.allow_file_creation ? 'd-none' : ''}", data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over_active_file'), :'data-url' => reload_exercise_path(@exercise), :'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-history', id: 'start-over-active-file-collapsed', label: '', title: t('exercises.editor.start_over_active_file'))
|
|
||||||
//- if !@course_token.blank?
|
//- if !@course_token.blank?
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-search', id: 'sidebar-search-collapsed', label: '', title: t('search.search_in_forum'))
|
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-search', id: 'sidebar-search-collapsed', label: '', title: t('search.search_in_forum'))
|
||||||
= render('editor_button', classes: 'btn-block btn-outline-danger btn enforce-top-margin', data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise), :'data-toggle' => 'tooltip', :'data-placement' => 'right'}, icon: 'fa fa-history', id: 'start-over-collapsed', label:'', title: t('exercises.editor.start_over'))
|
|
||||||
|
|
||||||
div.h-100.col-sm-12.enforce-bottom-margin id='sidebar-uncollapsed' class=(@exercise.hide_file_tree && @tips.blank? ? 'd-none' : '')
|
div.h-100.col-sm-12.enforce-bottom-margin id='sidebar-uncollapsed' class=(@exercise.hide_file_tree && @tips.blank? ? 'd-none' : '')
|
||||||
.position-absolute.d-flex.mb-1.w-100 style="overflow: auto; left: 0; top: 0; height: 100%;"
|
.position-absolute.d-flex.mb-1.w-100 style="overflow: auto; left: 0; top: 0; height: 100%;"
|
||||||
.w-100
|
.w-100
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn', icon: 'fa fa-minus-square', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar'))
|
= render('editor_button', classes: 'btn-block btn-outline-dark btn', icon: 'fa fa-minus-square', id: 'sidebar-collapse', label: t('exercises.editor.collapse_action_sidebar'))
|
||||||
|
|
||||||
div class=(@exercise.hide_file_tree ? 'd-none' : '')
|
- unless @exercise.hide_file_tree
|
||||||
hr
|
div
|
||||||
|
hr
|
||||||
|
|
||||||
#files data-entries=FileTree.new(files).to_js_tree
|
.card.border-secondary
|
||||||
|
.card-header.d-flex.justify-content-between.align-items-center.px-0.py-1
|
||||||
|
.px-2 = I18n.t('exercises.editor_file_tree.file_root')
|
||||||
|
div
|
||||||
|
- if @exercise.allow_file_creation
|
||||||
|
= render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip', :'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: '', title: t('exercises.editor.create_file'))
|
||||||
|
= render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip', :'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy') }, icon: 'far fa-trash-alt', id: 'destroy-file', label: '', title: t('exercises.editor.destroy_file'))
|
||||||
|
- unless @embed_options[:disable_download]
|
||||||
|
= render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip'}, icon: 'fas fa-arrow-down', id: 'download', label:'', title: t('exercises.editor.download'))
|
||||||
|
= render('editor_button', classes: 'btn-default btn-sm', data: {:'data-toggle' => 'tooltip', :'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise)}, icon: 'fa fa-history', id: 'start-over', label: '', title: t('exercises.editor.start_over'))
|
||||||
|
|
||||||
hr
|
.card-body.pt-0.pr-0.pl-1.pb-1
|
||||||
|
|
||||||
- if @exercise.allow_file_creation and not @exercise.hide_file_tree?
|
#files data-entries=FileTree.new(files).to_js_tree
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn', data: {:'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: t('exercises.editor.create_file'))
|
|
||||||
= render('editor_button', classes: 'btn-block btn-warning btn', data: {:'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy')}, icon: 'fa fa-times', id: 'destroy-file', label: t('exercises.editor.destroy_file'))
|
hr
|
||||||
|
|
||||||
- unless @embed_options[:disable_hints] or @tips.blank?
|
- unless @embed_options[:disable_hints] or @tips.blank?
|
||||||
= render(partial: 'tips_content')
|
= render(partial: 'tips_content')
|
||||||
.mb-4
|
.mb-4
|
||||||
|
|
||||||
- unless @embed_options[:disable_download]
|
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn enforce-top-margin', icon: 'fa fa-download', id: 'download', label: t('exercises.editor.download'))
|
|
||||||
= render('editor_button', classes: "btn-block btn-outline-warning btn #{@exercise.hide_file_tree || files.count < 2 && !@exercise.allow_file_creation ? 'd-none' : ''}", data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over_active_file'), :'data-url' => reload_exercise_path(@exercise)}, icon: 'fa fa-history', id: 'start-over-active-file', label: t('exercises.editor.start_over_active_file'))
|
|
||||||
= render('editor_button', classes: 'btn-block btn-outline-danger btn', data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(@exercise)}, icon: 'fa fa-history', id: 'start-over', label: t('exercises.editor.start_over'))
|
|
||||||
|
|
||||||
//- if !@course_token.blank?
|
//- if !@course_token.blank?
|
||||||
.input-group.enforce-top-margin
|
.input-group.enforce-top-margin
|
||||||
.enforce-right-margin
|
.enforce-right-margin
|
||||||
@ -48,4 +46,4 @@ div.h-100.col-sm-12.enforce-bottom-margin id='sidebar-uncollapsed' class=(@exerc
|
|||||||
i.fa.fa-search
|
i.fa.fa-search
|
||||||
|
|
||||||
- if @exercise.allow_file_creation?
|
- if @exercise.allow_file_creation?
|
||||||
= render('shared/modal', id: 'modal-file', template: 'code_ocean/files/_form', title: t('exercises.editor.create_file'))
|
= render('shared/modal', id: 'modal-file', template: 'code_ocean/files/_form', title: t('exercises.editor.create_file'))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.frame data-executable=file.file_type.executable? data-filename=file.name_with_extension data-renderable=file.file_type.renderable? data-role=file.role data-binary=file.file_type.binary? data-context-type=file.context_type
|
.frame data-executable=file.file_type.executable? data-filename=file.name_with_extension data-renderable=file.file_type.renderable? data-role=file.role data-binary=file.file_type.binary? data-context-type=file.context_type data-read-only=file.read_only
|
||||||
- if file.file_type.binary?
|
- if file.file_type.binary?
|
||||||
.binary-file data-file-id=file.ancestor_id
|
.binary-file data-file-id=file.ancestor_id
|
||||||
- if file.file_type.renderable?
|
- if file.file_type.renderable?
|
||||||
@ -12,4 +12,4 @@
|
|||||||
= link_to(file.native_file.file.filename, file.native_file.url)
|
= link_to(file.native_file.file.filename, file.native_file.url)
|
||||||
- else
|
- else
|
||||||
.editor-content.d-none data-file-id=file.ancestor_id = file.content
|
.editor-content.d-none data-file-id=file.ancestor_id = file.content
|
||||||
.editor data-file-id=file.ancestor_id data-indent-size=file.file_type.indent_size data-mode=file.file_type.editor_mode data-read-only=file.read_only data-allow-auto-completion=exercise.allow_auto_completion.to_s data-id=file.id
|
.editor data-file-id=file.ancestor_id data-indent-size=file.file_type.indent_size data-mode=file.file_type.editor_mode data-allow-auto-completion=exercise.allow_auto_completion.to_s data-id=file.id
|
@ -1,8 +1,8 @@
|
|||||||
div id='output_sidebar_collapsed'
|
div id='output_sidebar_collapsed'
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa fa-plus-square', id: 'toggle-sidebar-output-collapsed', label: '')
|
= render('editor_button', classes: 'btn-block btn-outline-dark btn', data: {:'data-toggle' => 'tooltip', :'data-placement' => 'left'}, title: t('exercises.editor.expand_output_sidebar'), icon: 'fa fa-plus-square', id: 'toggle-sidebar-output-collapsed', label: '')
|
||||||
div.h-100 id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-bottom-margin' data-message-no-output=t('exercises.implement.no_output_yet')
|
div.h-100 id='output_sidebar_uncollapsed' class='d-none col-sm-12 enforce-bottom-margin' data-message-no-output=t('exercises.implement.no_output_yet')
|
||||||
.row
|
.row
|
||||||
= render('editor_button', classes: 'btn-block btn-primary btn', icon: 'fa fa-minus-square', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar'))
|
= render('editor_button', classes: 'btn-block btn-outline-dark btn', icon: 'fa fa-minus-square', id: 'toggle-sidebar-output', label: t('exercises.editor.collapse_output_sidebar'))
|
||||||
|
|
||||||
div.position-absolute.d-flex.mb-1.w-100 style="overflow: auto; left: 0; bottom: 0; height: calc(100% - 3rem);"
|
div.position-absolute.d-flex.mb-1.w-100 style="overflow: auto; left: 0; bottom: 0; height: calc(100% - 3rem);"
|
||||||
div.w-100
|
div.w-100
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class FileTree < Tree::TreeNode
|
class FileTree
|
||||||
def file_icon(file)
|
def file_icon(file)
|
||||||
if file.file_type.audio?
|
if file.file_type.audio?
|
||||||
'fa fa-file-audio-o'
|
'fa fa-file-audio-o'
|
||||||
@ -26,9 +26,11 @@ class FileTree < Tree::TreeNode
|
|||||||
private :folder_icon
|
private :folder_icon
|
||||||
|
|
||||||
def initialize(files = [])
|
def initialize(files = [])
|
||||||
super(root_label)
|
# Our tree needs a root node, but we won't display it.
|
||||||
|
@root = Tree::TreeNode.new('ROOT')
|
||||||
|
|
||||||
files.uniq(&:name_with_extension).each do |file|
|
files.uniq(&:name_with_extension).each do |file|
|
||||||
parent = self
|
parent = @root
|
||||||
(file.path || '').split('/').each do |segment|
|
(file.path || '').split('/').each do |segment|
|
||||||
node = parent.children.detect {|child| child.name == segment } || parent.add(Tree::TreeNode.new(segment))
|
node = parent.children.detect {|child| child.name == segment } || parent.add(Tree::TreeNode.new(segment))
|
||||||
parent = node
|
parent = node
|
||||||
@ -60,15 +62,10 @@ class FileTree < Tree::TreeNode
|
|||||||
end
|
end
|
||||||
private :node_icon
|
private :node_icon
|
||||||
|
|
||||||
def root_label
|
|
||||||
I18n.t('exercises.editor_file_tree.file_root')
|
|
||||||
end
|
|
||||||
private :root_label
|
|
||||||
|
|
||||||
def to_js_tree
|
def to_js_tree
|
||||||
{
|
{
|
||||||
core: {
|
core: {
|
||||||
data: map_to_js_tree(self),
|
data: @root.children.map {|child| map_to_js_tree(child) },
|
||||||
},
|
},
|
||||||
}.to_json
|
}.to_json
|
||||||
end
|
end
|
||||||
|
@ -81,16 +81,16 @@ describe FileTree do
|
|||||||
|
|
||||||
it 'creates a root node' do
|
it 'creates a root node' do
|
||||||
# Instead of checking #initialize on the parent, we validate #set_as_root!
|
# Instead of checking #initialize on the parent, we validate #set_as_root!
|
||||||
expect(file_tree).to receive(:set_as_root!).and_call_original
|
expect(Tree::TreeNode).to receive(:new).and_call_original.at_least(:once)
|
||||||
file_tree.send(:initialize)
|
file_tree.send(:initialize)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates tree nodes for every file' do
|
it 'creates tree nodes for every file' do
|
||||||
expect(file_tree.select(&:content).map(&:content)).to eq(files)
|
expect(file_tree.instance_variable_get(:@root).select(&:content).map(&:content)).to eq(files)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates tree nodes for intermediary path segments' do
|
it 'creates tree nodes for intermediary path segments' do
|
||||||
expect(file_tree.reject(&:content).reject(&:is_root?).map(&:name)).to eq(files.first.path.split('/'))
|
expect(file_tree.instance_variable_get(:@root).reject(&:content).reject(&:is_root?).map(&:name)).to eq(files.first.path.split('/'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -179,8 +179,22 @@ describe FileTree do
|
|||||||
expect(js_tree).to be_a(String)
|
expect(js_tree).to be_a(String)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'produces the required JSON format' do
|
context 'without any file' do
|
||||||
expect(JSON.parse(js_tree).deep_symbolize_keys).to eq(core: {data: file_tree.send(:map_to_js_tree, file_tree)})
|
it 'produces the required JSON format' do
|
||||||
|
expect(JSON.parse(js_tree).deep_symbolize_keys).to eq(core: {data: []})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with files' do
|
||||||
|
let(:files) { FactoryBot.build_list(:file, 10, context: nil, path: 'foo/bar/baz') }
|
||||||
|
let(:file_tree) { described_class.new(files) }
|
||||||
|
let(:js_tree) { file_tree.to_js_tree }
|
||||||
|
|
||||||
|
it 'produces the required JSON format with a file' do
|
||||||
|
# We ignore the root node and only use the children here
|
||||||
|
child_tree = file_tree.send(:map_to_js_tree, file_tree.instance_variable_get(:@root).children.first)
|
||||||
|
expect(JSON.parse(js_tree).deep_symbolize_keys).to eq(core: {data: [child_tree]})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user