From accf0550d7505229fa36a5aaa00e3a9129777c41 Mon Sep 17 00:00:00 2001 From: Ralf Teusner Date: Wed, 12 Oct 2016 16:35:21 +0200 Subject: [PATCH] reworked the exercise edit dialog. Moved javascript part from editor_edit.js.erb to exercises.js.erb. Manipulated some further javascript as necessary. It is not super elegant, but this is due to the former structure of the code which uses cloned dummy forms. Integrating the ace editor made some strange calls necessary. Also fixed toggling the input area and the file upload dialog --- app/assets/javascripts/editor_edit.js.erb | 56 ----------------- app/assets/javascripts/exercises.js.erb | 70 +++++++++++++++++++++- app/assets/stylesheets/editor.css.scss | 10 ++++ app/views/exercises/_code_field.html.slim | 3 +- app/views/exercises/_editor_edit.html.slim | 4 +- app/views/exercises/_file_form.html.slim | 3 +- 6 files changed, 84 insertions(+), 62 deletions(-) diff --git a/app/assets/javascripts/editor_edit.js.erb b/app/assets/javascripts/editor_edit.js.erb index fa3d40fc..e69de29b 100644 --- a/app/assets/javascripts/editor_edit.js.erb +++ b/app/assets/javascripts/editor_edit.js.erb @@ -1,56 +0,0 @@ -$(function() { - // ruby part adds the relative_url_root, if it is set. - var ACE_FILES_PATH = '<%= (defined? config.relative_url_root) && config.relative_url_root != nil && config.relative_url_root != "" ? config.relative_url_root : "" %>' + '/assets/ace/'; - var THEME = 'ace/theme/textmate'; - - var configureEditors = function() { - _.each(['modePath', 'themePath', 'workerPath'], function(attribute) { - ace.config.set(attribute, ACE_FILES_PATH); - }); - }; - - var initializeEditors = function() { - $('.editor').each(function(index, element) { - var editor = ace.edit(element); - - var document = editor.getSession().getDocument(); - // insert pre-existing code into editor. we have to use insertLines, otherwise the deltas are not properly added - var file_id = $(element).data('file-id'); - var content = $('.editor-content[data-file-id=' + file_id + ']'); - - document.insertLines(0, content.text().split(/\n/)); - // remove last (empty) that is there by default line - document.removeLines(document.getLength() - 1, document.getLength() - 1); - editor.setReadOnly($(element).data('read-only') !== undefined); - editor.setShowPrintMargin(false); - editor.setTheme(THEME); - - var textarea = $('textarea[id="exercise_files_attributes_'+index+'_content"]'); - var content = textarea.val(); - - if (content != undefined) - { - editor.getSession().setValue(content); - editor.getSession().on('change', function(){ - textarea.val(editor.getSession().getValue()); - }); - } - - editor.commands.bindKey("ctrl+alt+0", null); - var session = editor.getSession(); - session.setMode($(element).data('mode')); - session.setTabSize($(element).data('indent-size')); - session.setUseSoftTabs(true); - session.setUseWrapMode(true); - - var file_id = $(element).data('id'); - } - )}; - - if ($('#editor-edit').isPresent()) { - configureEditors(); - initializeEditors(); - $('.frame').show(); - } -}); - diff --git a/app/assets/javascripts/exercises.js.erb b/app/assets/javascripts/exercises.js.erb index 26e76218..73799bec 100644 --- a/app/assets/javascripts/exercises.js.erb +++ b/app/assets/javascripts/exercises.js.erb @@ -1,13 +1,68 @@ $(function() { + // ruby part adds the relative_url_root, if it is set. + var ACE_FILES_PATH = '<%= (defined? config.relative_url_root) && config.relative_url_root != nil && config.relative_url_root != "" ? config.relative_url_root : "" %>' + '/assets/ace/'; + var THEME = 'ace/theme/textmate'; + var TAB_KEY_CODE = 9; var execution_environments; var file_types; + + + var configureEditors = function() { + _.each(['modePath', 'themePath', 'workerPath'], function(attribute) { + ace.config.set(attribute, ACE_FILES_PATH); + }); + }; + + var initializeEditor = function(index, element) { + var editor = ace.edit(element); + + var document = editor.getSession().getDocument(); + // insert pre-existing code into editor. we have to use insertLines, otherwise the deltas are not properly added + var file_id = $(element).data('file-id'); + var content = $('.editor-content[data-file-id=' + file_id + ']'); + + document.insertLines(0, content.text().split(/\n/)); + // remove last (empty) that is there by default line + document.removeLines(document.getLength() - 1, document.getLength() - 1); + editor.setReadOnly($(element).data('read-only') !== undefined); + editor.setShowPrintMargin(false); + editor.setTheme(THEME); + + var textarea = $('textarea[id="exercise_files_attributes_'+index+'_content"]'); + var content = textarea.val(); + + if (content != undefined) + { + editor.getSession().setValue(content); + editor.getSession().on('change', function(){ + textarea.val(editor.getSession().getValue()); + }); + } + + editor.commands.bindKey("ctrl+alt+0", null); + var session = editor.getSession(); + session.setMode($(element).data('mode')); + session.setTabSize($(element).data('indent-size')); + session.setUseSoftTabs(true); + session.setUseWrapMode(true); + } + + var initializeEditors = function() { + // initialize ace editors for all code textareas in the dom except the last one. The last one is the dummy area for new files, which is cloned when needed. + // this one must NOT! be initialized. + $('.editor:not(:last)').each(initializeEditor) + }; + var addFileForm = function(event) { event.preventDefault(); var element = $('#dummies').children().first().clone(); - var html = $('
').append(element).html().replace(/index/g, new Date().getTime()); + + // the timestamp is used here, since it is most probably unique. This is strange, but was originally designed that way. + var latestTextAreaIndex = new Date().getTime(); + var html = $('
').append(element).html().replace(/index/g, latestTextAreaIndex); $('#files').append(html); $('#files li:last select[name*="file_type_id"]').val(getSelectedExecutionEnvironment().file_type_id); $('#files li:last select').chosen(window.CodeOcean.CHOSEN_OPTIONS); @@ -15,6 +70,10 @@ $(function() { // if we collapse the file forms by default, we need to click on the new element in order to open it. // however, this crashes for more files (if we add several ones by clicking the add button more often), since the elements are probably not correctly added to the files list. //$('#files li:last>div:first>a>div').click(); + + // initialize the ace editor for the new textarea. + // pass the correct index and the last ace editor under the node files. this is the last one, since we just added it. + initializeEditor(latestTextAreaIndex, $('#files .editor').last()[0]); }; var ajaxError = function() { @@ -193,4 +252,13 @@ $(function() { highlightCode(); } } + + + if ($('#editor-edit').isPresent()) { + configureEditors(); + initializeEditors(); + $('.frame').show(); + } + + }); diff --git a/app/assets/stylesheets/editor.css.scss b/app/assets/stylesheets/editor.css.scss index e62c4f89..755e3409 100644 --- a/app/assets/stylesheets/editor.css.scss +++ b/app/assets/stylesheets/editor.css.scss @@ -7,6 +7,16 @@ button i.fa-spin { width: 100%; } +/* this class is used for the edit view of an exercise. It needs the height set, as it does not automatically resize */ +.edit-frame { + height: 400px; + + audio, img, video { + max-width: 100%; + } +} + + .frame { display: none; diff --git a/app/views/exercises/_code_field.html.slim b/app/views/exercises/_code_field.html.slim index 5273a693..bb2a806f 100644 --- a/app/views/exercises/_code_field.html.slim +++ b/app/views/exercises/_code_field.html.slim @@ -2,5 +2,6 @@ = form.label(attribute, label) |   a.toggle-input data={text_initial: t('shared.upload_file'), text_toggled: t('shared.back')} href='#' = t('shared.upload_file') - = form.text_area(attribute, class: 'code-field form-control original-input', rows: 16, style: "display:none;") + = form.text_area(attribute, class: 'code-field form-control', rows: 16, style: "display:none;") = form.file_field(attribute, class: 'alternative-input form-control', disabled: true) + = render partial: 'editor_edit', locals: { exercise: @exercise } diff --git a/app/views/exercises/_editor_edit.html.slim b/app/views/exercises/_editor_edit.html.slim index 810653d2..83f27d68 100644 --- a/app/views/exercises/_editor_edit.html.slim +++ b/app/views/exercises/_editor_edit.html.slim @@ -1,5 +1,5 @@ -#editor-edit.panel-group.row data-exercise-id=@exercise.id +#editor-edit.panel-group.row.original-input data-exercise-id=@exercise.id #frames - .frame + .edit-frame .editor-content.hidden .editor \ No newline at end of file diff --git a/app/views/exercises/_file_form.html.slim b/app/views/exercises/_file_form.html.slim index 796c6722..065eca66 100644 --- a/app/views/exercises/_file_form.html.slim +++ b/app/views/exercises/_file_form.html.slim @@ -37,5 +37,4 @@ li.panel.panel-default .form-group = f.label(:role, t('activerecord.attributes.file.weight')) = f.number_field(:weight, class: 'form-control', min: 1, step: 'any') - = render('code_field', attribute: :content, form: f, label: t('activerecord.attributes.file.content')) - = render partial: 'editor_edit', locals: { exercise: @exercise } \ No newline at end of file + = render('code_field', attribute: :content, form: f, label: t('activerecord.attributes.file.content')) \ No newline at end of file