Editor client javascript and css

This commit is contained in:
Vivek Santayana 2022-06-22 01:58:36 +01:00
parent 8eb7fb6869
commit c04c824585
3 changed files with 276 additions and 236 deletions

View File

@ -13,8 +13,7 @@
} }
.editor-controls a { .editor-controls a {
margin: 0 10px; margin: 10px 10px;
z-index: 10;
} }
.editor-controls a i { .editor-controls a i {
@ -67,3 +66,22 @@
.panel-button i { .panel-button i {
font-size: larger; font-size: larger;
} }
.editor-panel, .info-panel {
margin: 30pt auto;
}
.info-panel {
display: none;
}
.control-panel {
margin-left: auto;
margin-right: 0;
width:fit-content;
}
#alert-box {
margin: 30px auto;
max-width: 460px;
}

View File

@ -1,35 +1,184 @@
const root = $('#editor-root') // Variable Declarations
Sortable.create(root.get(0), {handle: '.move-handle', onEnd: function(evt) {renumber_blocks()}}) const $root = $('#editor-root')
const target = $root.data('target')
const id = $root.data('id')
const $control_panel = $('.control-panel')
const $info_panel = $('.info-panel')
const $editor_panel = $('.editor-panel')
var element_index = 0 var element_index = 0
var question_index = 0
root.on('click', '.panel-controls > a', function(event) { // Initialise Sortable and trigger renumbering on end of drag
Sortable.create($root.get(0), {handle: '.move-handle', onEnd: function(evt) {renumber_blocks()}})
// Info Button Listener
$control_panel.find('button').click(function(event){
if ($info_panel.is(":hidden")) {
$editor_panel.hide()
$info_panel.fadeIn()
$(this).addClass('active')
} else {
$info_panel.hide()
$editor_panel.fadeIn()
$(this).removeClass('active')
}
event.preventDefault()
})
// Control Button Listeners
$root.on('click', '.block-controls > a', function(event){
event.preventDefault()
var action = $(this).data('action')
var root_accordion = $(this).closest('div').siblings('.accordion')
if (action == 'add-question') {
var question = generate_single_question(root_container_id=`#${root_accordion.attr('id')}`)
$(question).appendTo(root_accordion).hide().fadeIn()
if (root_accordion.children().length > 1 ) {
root_accordion.find('.panel-controls > a[data-action="delete"]').removeClass('disabled')
} else {
root_accordion.find('.panel-controls > a[data-action="delete"]').addClass('disabled')
}
renumber_blocks()
}
})
$root.on('click', '.panel-controls > a', function(event) {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
var action = $(this).data('action') var action = $(this).data('action')
var element = $(this).closest('.accordion-item') var element = $(this).closest('.accordion-item')
var root_container = $(this).closest('.accordion') var root_container = $(this).closest('.accordion')
if (action == 'delete') { if (action == 'delete') {
element.remove() element.fadeOut(function(){
console.log(root_container.get(0) == root.get(0)) $(this).remove()
if (root_container.get(0) != root.get(0) && root_container.children().length < 2 ) { renumber_blocks()
if (root_container.get(0) != $root.get(0) && root_container.children().length < 2 ) {
root_container.find('.panel-controls > a[data-action="delete"]').addClass('disabled') root_container.find('.panel-controls > a[data-action="delete"]').addClass('disabled')
} }
})
} else if (action == 'add-question') { } else if (action == 'add-question') {
var question = generate_single_question(root_container_id=`#${root_container.attr('id')}`) var question = generate_single_question(root_container_id=`#${root_container.attr('id')}`)
$(question).insertBefore(element) $(question).insertBefore(element).hide().fadeIn()
if (root_container.get(0) != root.get(0) && root_container.children().length > 1 ) { if (root_container.get(0) != $root.get(0) && root_container.children().length > 1 ) {
root_container.find('.panel-controls > a[data-action="delete"]').removeClass('disabled') root_container.find('.panel-controls > a[data-action="delete"]').removeClass('disabled')
} }
} else if (action == 'add-block') { } else if (action == 'add-block') {
var block = generate_block(root_container_id=`#${root_container.attr('id')}`) var block = generate_block(root_container_id=`#${root_container.attr('id')}`)
$(block).insertBefore(element) $(block).insertBefore(element).hide().fadeIn()
var block_container = $(`#element${element_index-1}`).children().find('.accordion')
Sortable.create(block_container.get(0), {handle: '.move-handle', onEnd: function(evt) {renumber_blocks()}})
var question = generate_single_question(root_container_id=`#${block_container.attr('id')}`)
block_container.append(question)
block_container.find('.panel-controls > a[data-action="delete"]').addClass('disabled')
} }
renumber_blocks() renumber_blocks()
}) })
root.on('change', '.form-select.question-type', function(event) { $root.on('click', '.option-controls > a', function(event) {
event.preventDefault()
var action = $(this).data('action')
var options = $(this).closest('div.option-controls').siblings('.options')
var length = options.children().length
var correct = $(this).closest('div.option-controls').siblings().find('.question-correct')
if (action == 'delete') {
if (length > 2) {
options.children().last().fadeOut(function(){
$(this).remove()
length = options.children().length
if (length <= 2) {
options.siblings('div.option-controls').children('a[data-action="delete"]').addClass('disabled')
} else {
options.siblings('div.option-controls').children('a[data-action="delete"]').removeClass('disabled')
}
})
correct.children().last().fadeOut(function(){
$(this).remove()
})
}
} else {
var opt = `
<div class="input-group mb-3">
<span class="input-group-text">${length}</span>
<input type="text" class="form-control" value="Option ${length}">
</div>
`
$(opt).appendTo(options).hide().fadeIn()
var cor = `<option value="${length}">${length}</option>`
correct.append(cor)
}
length = options.children().length
if (length <= 2) {
$(this).closest('div.option-controls').children('a[data-action="delete"]').addClass('disabled')
} else {
$(this).closest('div.option-controls').children('a[data-action="delete"]').removeClass('disabled')
}
})
$('.editor-controls > a').click(function(event){
event.preventDefault()
var action = $(this).data('action')
var root_accordion = $(this).closest('div').siblings('.accordion')
if (action == 'add-question') {
var obj = generate_single_question(root_container_id=`#${root_accordion.attr('id')}`)
$(obj).appendTo($root).hide().fadeIn()
} else if (action == 'add-block') {
var obj = generate_block(root_container_id=`#${root_accordion.attr('id')}`)
$(obj).appendTo($root).hide().fadeIn()
var block_container = $(`#element${element_index-1}`).children().find('.accordion')
Sortable.create(block_container.get(0), {handle: '.move-handle', onEnd: function(evt) {renumber_blocks()}})
var question = generate_single_question(root_container_id=`#${block_container.attr('id')}`)
block_container.append(question)
block_container.find('.panel-controls > a[data-action="delete"]').addClass('disabled')
} else if (action == 'discard') {
window.location.href = '/admin/settings/questions/'
} else if (action == 'delete') {
$.ajax({
url: '/admin/settings/questions/delete/',
type: 'POST',
data: JSON.stringify({
'id': id,
'action': action
}),
contentType: 'application/json',
success: function(response) {
window.location.href = '/admin/settings/questions/'
},
error: function(response) {
error_response(response)
}
})
} else if (action == 'save') {
var input = parse_input()
var def = $('.dataset-default').is(':checked')
var name = $('.dataset-name').val()
var creator = $('.dataset-creator').val()
console.log([def, name, creator])
$.ajax({
url: target,
type: 'POST',
data: JSON.stringify({
'id': id,
'action': 'upload',
'data': input,
'default': def,
'name': name,
'creator': creator
}),
contentType: 'application/json',
success: function(response) {
window.location.href = '/admin/settings/questions/'
},
error: function(response) {
error_response(response)
}
})
}
renumber_blocks()
})
// Question Type Select Menu Listener
$root.on('change', '.form-select.question-type', function(event) {
event.preventDefault() event.preventDefault()
var type = $(this).val() var type = $(this).val()
var options = $(this).closest('div.input-group').siblings('.options') var options = $(this).closest('div.input-group').siblings('.options')
@ -48,7 +197,7 @@ root.on('change', '.form-select.question-type', function(event) {
<input type="text" class="form-control" value="No" disabled> <input type="text" class="form-control" value="No" disabled>
</div> </div>
` `
options.append(opt) $(opt).appendTo(options).hide().fadeIn()
option_controls.children('a').addClass('disabled') option_controls.children('a').addClass('disabled')
var cor = ` var cor = `
<option value ="0" default>0</option> <option value ="0" default>0</option>
@ -64,66 +213,65 @@ root.on('change', '.form-select.question-type', function(event) {
} }
}) })
root.on('click', '.option-controls > a', function(event) { // Data and Rendering Functions
event.preventDefault() function renumber_blocks () {
var action = $(this).data('action') $( ".block-number" ).each(function(index) {
var options = $(this).closest('div.option-controls').siblings('.options') $( this ).text($( this ).closest('.accordion-item').index() + 1)
var length = options.children().length })
var correct = $(this).closest('div.option-controls').siblings().find('.question-correct') }
if (action == 'delete') {
if (length > 2) {
options.children().last().remove()
correct.children().last().remove()
}
} else {
var opt = `
<div class="input-group mb-3">
<span class="input-group-text">${length}</span>
<input type="text" class="form-control" value="Option ${length}">
</div>
`
options.append(opt)
var cor = `<option value="${length}">${length}</option>`
correct.append(cor)
}
length = options.children().length
if (length <= 2) {
$(this).closest('div.option-controls').children('a[data-action="delete"]').addClass('disabled')
} else {
$(this).closest('div.option-controls').children('a[data-action="delete"]').removeClass('disabled')
}
})
function parse_input() {
var data = []
$('.editor-controls > a').click(function(event){ var element = {}
event.preventDefault() var question = {}
var action = $(this).data('action') var block_container
var root_accordion = $(this).closest('div').siblings('.accordion') var q_no = 0
if (action == 'add-question') { $root.children().each(function(index) {
var obj = generate_single_question(root_container_id=`#${root_accordion.attr('id')}`) element = {}
root.append(obj) if ($(this).data('type') == 'block') {
} else if (action == 'add-block') { element['type'] = 'block'
var obj = generate_block(root_container_id=`#${root_accordion.attr('id')}`) element['question_header'] = $(this).find('.block-header-text').val()
root.append(obj) element['questions'] = []
var block_container = $(`#element${element_index-1}`).children().find('.accordion') block_container = $(this).children().find('.accordion')
Sortable.create(block_container.get(0), {handle: '.move-handle', onEnd: function(evt) {renumber_blocks()}}) block_container.children().each(function(index) {
var question = generate_single_question(root_container_id=`#${block_container.attr('id')}`) question = {}
block_container.append(question) question['q_no'] = q_no
block_container.find('.panel-controls > a[data-action="delete"]').addClass('disabled') question['text'] = $(this).find('.question-text').val()
} else if (action == 'done') { question['q_type'] = $(this).find('.question-type').val()
parse_data(data) question['correct'] = parseInt($(this).find('.question-correct').val())
question['options'] = []
$(this).find('.options').find('input').each(function(index) {
question['options'].push($(this).val())
})
question['tags'] = $(this).find('.question-tags').val().split('\r\n')
element['questions'].push(question)
q_no ++
})
} else if ( $(this).data('type') == 'question') {
element['type'] = 'question'
element['q_no'] = q_no
element['text'] = $(this).find('.question-text').val()
element['q_type'] = $(this).find('.question-type').val()
element['correct'] = parseInt($(this).find('.question-correct').val())
element['options'] = []
$(this).find('.options').find('input').each(function(index) {
element['options'].push($(this).val())
})
element['tags'] = $(this).find('.question-tags').val().split('\r\n')
q_no ++
} }
renumber_blocks() data.push(element)
}) })
return data
}
function parse_data(data) { function parse_data(data) {
var block, obj, new_block, block_container, question, _question, new_question, options, correct, opt, tags var block, obj, new_block, block_container, question, _question, new_question, options, correct, opt, tags
for (let c = 0; c < data.length; c++) { for (let c = 0; c < data.length; c++) {
block = data[c] block = data[c]
if (block['type'] == 'block') { if (block['type'] == 'block') {
obj = generate_block(root_container_id=`#${root.attr('id')}`) obj = generate_block(root_container_id=`#${$root.attr('id')}`)
root.append(obj) $root.append(obj)
new_block = $(`#element${element_index-1}`) new_block = $(`#element${element_index-1}`)
new_block.find('.block-header-text').val(block['question_header']).trigger('change') new_block.find('.block-header-text').val(block['question_header']).trigger('change')
block_container = $(`#element${element_index-1}`).children().find('.accordion') block_container = $(`#element${element_index-1}`).children().find('.accordion')
@ -163,8 +311,8 @@ function parse_data(data) {
} }
} else { } else {
question = block question = block
obj = generate_single_question(root_container_id=`#${root.attr('id')}`) obj = generate_single_question(root_container_id=`#${$root.attr('id')}`)
root.append(obj) $root.append(obj)
new_question = $(`#element${element_index-1}`) new_question = $(`#element${element_index-1}`)
new_question.find('.question-text').val(question['text']).trigger('change') new_question.find('.question-text').val(question['text']).trigger('change')
new_question.find('.question-type').val(question['q_type']).trigger('change') new_question.find('.question-type').val(question['q_type']).trigger('change')
@ -193,24 +341,9 @@ function parse_data(data) {
renumber_blocks() renumber_blocks()
} }
root.on('click', '.block-controls > a', function(event){ // Content Generator Functions
event.preventDefault()
var action = $(this).data('action')
var root_accordion = $(this).closest('div').siblings('.accordion')
if (action == 'add-question') {
var question = generate_single_question(root_container_id=`#${root_accordion.attr('id')}`)
root_accordion.append(question)
if (root_accordion.children().length > 1 ) {
root_accordion.find('.panel-controls > a[data-action="delete"]').removeClass('disabled')
} else {
root_accordion.find('.panel-controls > a[data-action="delete"]').addClass('disabled')
}
renumber_blocks()
}
})
function generate_single_question(root_container_id) { function generate_single_question(root_container_id) {
if (root_container_id == `#${root.attr('id')}`) { if (root_container_id == `#${$root.attr('id')}`) {
var block_button = ` var block_button = `
<a href="javascript:void(0)" class="btn btn-primary" data-action="add-block" title="Add Block Above" aria-title="Add Block Above" data-bs-toggle="collapse" data-bs-target> <a href="javascript:void(0)" class="btn btn-primary" data-action="add-block" title="Add Block Above" aria-title="Add Block Above" data-bs-toggle="collapse" data-bs-target>
<i class="bi bi-folder-plus"></i> <i class="bi bi-folder-plus"></i>
@ -220,7 +353,7 @@ function generate_single_question(root_container_id) {
var block_button = '' var block_button = ''
} }
var question = ` var question = `
<div class="accordion-item" id="element${element_index}"> <div class="accordion-item" id="element${element_index}" data-type="question">
<h2 class="accordion-header" id="element${element_index}-header"> <h2 class="accordion-header" id="element${element_index}-header">
<div class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#element${element_index}-content" aria-expanded="true" aria-controls="element${element_index}-content"> <div class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#element${element_index}-content" aria-expanded="true" aria-controls="element${element_index}-content">
<div class="float-start"> <div class="float-start">
@ -238,7 +371,7 @@ function generate_single_question(root_container_id) {
<i class="bi bi-file-plus-fill"></i> <i class="bi bi-file-plus-fill"></i>
</a> </a>
<a href="javascript:void(0)" class="btn btn-danger" data-action="delete" title="Delete Block" aria-title="Delete Block" data-bs-toggle="collapse" data-bs-target> <a href="javascript:void(0)" class="btn btn-danger" data-action="delete" title="Delete Block" aria-title="Delete Block" data-bs-toggle="collapse" data-bs-target>
<i class="bi bi-x-square-fill"></i> <i class="bi bi-trash-fill"></i>
</a> </a>
</div> </div>
</div> </div>
@ -299,7 +432,7 @@ function generate_single_question(root_container_id) {
function generate_block(root_container_id) { function generate_block(root_container_id) {
var block = ` var block = `
<div class="accordion-item" id="element${element_index}"> <div class="accordion-item" id="element${element_index}" data-type="block">
<h2 class="accordion-header" id="element${element_index}-header"> <h2 class="accordion-header" id="element${element_index}-header">
<div class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#element${element_index}-content" aria-expanded="true" aria-controls="element${element_index}-content"> <div class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#element${element_index}-content" aria-expanded="true" aria-controls="element${element_index}-content">
<div class="float-start"> <div class="float-start">
@ -319,7 +452,7 @@ function generate_block(root_container_id) {
<i class="bi bi-file-plus-fill"></i> <i class="bi bi-file-plus-fill"></i>
</a> </a>
<a href="javascript:void(0)" class="btn btn-danger" data-action="delete" title="Delete Block" aria-title="Delete Block" data-bs-toggle="collapse" data-bs-target> <a href="javascript:void(0)" class="btn btn-danger" data-action="delete" title="Delete Block" aria-title="Delete Block" data-bs-toggle="collapse" data-bs-target>
<i class="bi bi-x-square-fill"></i> <i class="bi bi-trash-fill"></i>
</a> </a>
</div> </div>
</div> </div>
@ -346,14 +479,21 @@ function generate_block(root_container_id) {
return block return block
} }
var myArray = [ // Fetch data once page finishes loading
"Apples", $(window).on('load', function() {
"Bananas", $.ajax({
"Pears" url: target,
]; type: 'POST',
data: JSON.stringify({
function renumber_blocks () { 'id': id,
$( ".block-number" ).each(function(index) { 'action': 'fetch'
$( this ).text($( this ).closest('.accordion-item').index()) }),
contentType: 'application/json',
success: function(response) {
parse_data(response['data'])
},
error: function(response) {
console.log(response)
}
}) })
} })

View File

@ -42,81 +42,6 @@ $('form.form-post').submit(function(event) {
event.preventDefault(); event.preventDefault();
}); });
// Form Upload Questions - Special case, needs to handle files.
$('form[name=form-upload-questions]').submit(function(event) {
var $form = $(this);
var data = new FormData($form[0]);
var file = $('input[name=data_file]')[0].files[0]
data.append('file', file)
$.ajax({
url: window.location.pathname,
type: 'POST',
data: data,
processData: false,
contentType: false,
success: function(response) {
window.location.reload();
},
error: function(response) {
error_response(response);
}
});
event.preventDefault();
});
// Edit and Delete Test Button Handlers
$('.test-action').click(function(event) {
let id = $(this).data('id');
let action = $(this).data('action');
if (action == 'delete' || action == 'start' || action == 'end') {
$.ajax({
url: `/admin/tests/edit/`,
type: 'POST',
data: JSON.stringify({'id': id, 'action': action}), // TODO Change how CRUD operations work
contentType: 'application/json',
success: function(response) {
window.location.href = '/admin/tests/';
},
error: function(response){
error_response(response);
},
});
} else if (action == 'edit') {
window.location.href = `/admin/test/${id}/`
}
event.preventDefault();
});
// Edit Dataset Button Handlers
$('.edit-question-dataset').click(function(event) {
var filename = $(this).data('filename');
var action = $(this).data('action');
var disabled = $(this).hasClass('disabled');
if ( !disabled ) {
$.ajax({
url: `/admin/settings/questions/${action}/`,
type: 'POST',
data: JSON.stringify({'filename': filename}),
contentType: 'application/json',
success: function(response) {
window.location.reload();
},
error: function(response){
error_response(response);
},
});
};
event.preventDefault();
});
function error_response(response) { function error_response(response) {
const $alert = $("#alert-box"); const $alert = $("#alert-box");
@ -168,66 +93,23 @@ $('#dismiss-cookie-alert').click(function(event){
event.preventDefault(); event.preventDefault();
}) })
// Script for Result Actions // Create New Dataset
$('.result-action-buttons').click(function(event){ $('.create-new-dataset').click(function(event){
var id = $(this).data('id');
if ($(this).data('result-action') == 'generate') {
$.ajax({ $.ajax({
url: '/admin/certificate/', url: '/api/editor/new/',
type: 'POST', type: 'POST',
data: JSON.stringify({'id': id}), data: {
contentType: 'application/json', time: Date.now()
dataType: 'html',
success: function(response) {
var display_window = window.open();
display_window.document.write(response);
}, },
error: function(response){ dataType: 'json',
error_response(response); success: function(response){
}, if (response.redirect_to) {
}); window.location.href = response.redirect_to;
} else {
var action = $(this).data('result-action')
$.ajax({
url: window.location.href,
type: 'POST',
data: JSON.stringify({'id': id, 'action': action}),
contentType: 'application/json',
success: function(response) {
if (action == 'delete') {
window.location.href = '/admin/results/';
} else window.location.reload();
},
error: function(response){
error_response(response);
},
});
} }
event.preventDefault();
});
// Script for Deleting Time Adjustment
$('.adjustment-delete').click(function(event){
var user_code = $(this).data('user_code');
var location = window.location.href;
location = location.replace('#', '')
$.ajax({
url: location + 'delete-adjustment/',
type: 'POST',
data: JSON.stringify({'user_code': user_code}),
contentType: 'application/json',
success: function(response) {
window.location.reload();
}, },
error: function(response){ error: function(response){
error_response(response); console.log(response);
}, }
}); })
event.preventDefault()
event.preventDefault(); })
});