styled site with bootstrap, did some minor ui improvements and fixes
This commit is contained in:
parent
7f04d1e502
commit
1c0927ca1c
12 changed files with 233 additions and 52 deletions
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-02-21 17:05
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('elearning', '0017_auto_20160214_1534'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='useranswer',
|
||||
name='correct',
|
||||
field=models.NullBooleanField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='setting',
|
||||
name='logo',
|
||||
field=models.CharField(default='test', max_length=256),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-02-21 17:54
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('elearning', '0018_auto_20160221_1705'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='setting',
|
||||
old_name='button_solution',
|
||||
new_name='text_solution',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='setting',
|
||||
name='text_answer',
|
||||
field=models.CharField(max_length=100, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='option',
|
||||
name='text',
|
||||
field=models.CharField(max_length=256, null=True),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-02-21 20:50
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('elearning', '0019_auto_20160221_1754'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='setting',
|
||||
name='text_next',
|
||||
field=models.CharField(max_length=100, null=True),
|
||||
),
|
||||
]
|
|
@ -12,11 +12,13 @@ class Setting(models.Model):
|
|||
message_welcome_user = models.TextField(null=True)
|
||||
message_access_denied = models.TextField(null=True)
|
||||
message_already_answered = models.TextField(null=True)
|
||||
button_solution = models.CharField(max_length=100, null=True)
|
||||
text_answer = models.CharField(max_length=100, null=True)
|
||||
text_solution = models.CharField(max_length=100, null=True)
|
||||
text_next = models.CharField(max_length=100, null=True)
|
||||
logo = models.CharField(max_length=256, null=False)
|
||||
active = models.BooleanField(unique=True, default=False)
|
||||
|
||||
def __str__(self):
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
|
||||
|
@ -26,16 +28,16 @@ class Question(models.Model):
|
|||
text = models.TextField(null=True)
|
||||
explanation = models.TextField(null=True)
|
||||
|
||||
def __str__(self):
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
|
||||
class Option(models.Model):
|
||||
text = models.CharField(max_length=100, null=True)
|
||||
text = models.CharField(max_length=256, null=True)
|
||||
correct = models.BooleanField(null=False, default=False)
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE, null=False)
|
||||
|
||||
def __str__(self):
|
||||
def __unicode__(self):
|
||||
return self.text
|
||||
|
||||
|
||||
|
@ -49,7 +51,7 @@ class User(models.Model):
|
|||
name = models.CharField(max_length=100, null=False)
|
||||
last_seen = models.DateTimeField(null=True)
|
||||
|
||||
def __str__(self):
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
|
@ -58,8 +60,8 @@ class UserAnswer(models.Model):
|
|||
question = models.ForeignKey(Question, on_delete=models.CASCADE, null=False)
|
||||
correct = models.NullBooleanField(null=True)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user) + " - " + str(self.question)
|
||||
def __unicode__(self):
|
||||
return str(self.user) + " - " + str(self.question.id)
|
||||
|
||||
class Meta:
|
||||
unique_together = (('user', 'question'),)
|
||||
|
@ -71,3 +73,6 @@ class UserAnswerOptions(models.Model):
|
|||
|
||||
class Meta:
|
||||
unique_together = (('user_answer', 'option'),)
|
||||
|
||||
def __unicode__(self):
|
||||
return str(self.user_answer) + " - " + str(self.option)
|
||||
|
|
|
@ -34,12 +34,8 @@ p[id^="explanation_"] {
|
|||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.correct {
|
||||
outline: 4px solid #00a353;
|
||||
}
|
||||
|
||||
.failed {
|
||||
outline: 4px solid #a60000;
|
||||
.margin75 {
|
||||
margin-top: 75px;
|
||||
}
|
||||
|
||||
.mainLogo {
|
||||
|
@ -55,3 +51,7 @@ p[id^="explanation_"] {
|
|||
.table_headline {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #b3b3b3
|
||||
}
|
|
@ -59,8 +59,8 @@ function toggle_solution(id)
|
|||
function show_solution(id)
|
||||
{
|
||||
var element = document.getElementById("explanation_" + id);
|
||||
if (element.className == "hide") {
|
||||
element.className = "show";
|
||||
if (element.className.indexOf("hide") > -1) {
|
||||
element.className = element.className.replace("hide", "show");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,9 +76,10 @@ function get_answer(id) {
|
|||
if (answerRequest.readyState==4){
|
||||
if (answerRequest.status==200 || window.location.href.indexOf("http")==-1){
|
||||
parseResponse(id, answerRequest.responseText);
|
||||
setButtonToNext(id);
|
||||
}
|
||||
else{
|
||||
alert("An error has occured making the request");
|
||||
alert("Sorry, sending your answer was not successful!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +92,35 @@ function get_answer(id) {
|
|||
answerRequest.send(null)
|
||||
}
|
||||
|
||||
function setButtonToNext(id) {
|
||||
button = document.getElementById('showSolution_' + id);
|
||||
button.className = button.className.replace("show", "hide");
|
||||
|
||||
if(getNextQuestion(id)) {
|
||||
button = document.getElementById('next_' + id);
|
||||
button.className = button.className.replace("hide", "show");
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToNextQuestion(id) {
|
||||
var nextQuestion = getNextQuestion(id);
|
||||
|
||||
if(nextQuestion) {
|
||||
location.href = "#" + nextQuestion.id;
|
||||
}
|
||||
}
|
||||
|
||||
function getNextQuestion(id) {
|
||||
var questions = document.getElementsByName("question");
|
||||
|
||||
for(var i = 0; i < questions.length; i++) {
|
||||
if(questions[i].id == "question_" + id) {
|
||||
return questions[i+1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getCheckboxAnswers(id) {
|
||||
|
||||
var answers = [];
|
||||
|
@ -107,32 +137,45 @@ function getCheckboxAnswers(id) {
|
|||
|
||||
function parseResponse(id, responseText) {
|
||||
|
||||
var correctOptions = JSON.parse(responseText);
|
||||
var correctOptions = JSON.parse(responseText).options_id;
|
||||
var progress = JSON.parse(responseText).progress;
|
||||
|
||||
setCorrectOptions(correctOptions, id)
|
||||
setProgress(progress)
|
||||
}
|
||||
|
||||
function setCorrectOptions(correctOptions, id) {
|
||||
var elements = document.getElementsByName("checkbox_" + id);
|
||||
var holders = document.getElementsByName("checkbox_div_" + id);
|
||||
|
||||
for(var i = 0; i < elements.length; i++) {
|
||||
var element = elements[i];
|
||||
element.className="";
|
||||
for(var i = 0; i < elements.length; i++) {
|
||||
var element = elements[i];
|
||||
var holder = holders[i];
|
||||
|
||||
var correct = isCorrectOption(element.value);
|
||||
if(correct) {
|
||||
element.className="correct";
|
||||
} else {
|
||||
if(element.checked) {
|
||||
element.className="failed";
|
||||
var correct = isCorrectOption(element.value);
|
||||
if(correct) {
|
||||
holder.className = holder.className + " list-group-item-success";
|
||||
} else {
|
||||
if(element.checked) {
|
||||
holder.className = holder.className + " list-group-item-danger";;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
element.disabled = true;
|
||||
}
|
||||
|
||||
function isCorrectOption(option) {
|
||||
for(var i = 0; i < correctOptions.length; i++) {
|
||||
if(correctOptions[i] == option) {
|
||||
return true;
|
||||
function isCorrectOption(option) {
|
||||
for(var i = 0; i < correctOptions.length; i++) {
|
||||
if(correctOptions[i] == option) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setProgress(progress) {
|
||||
progressbar = document.getElementById("progressbar");
|
||||
progressbar.style.width = progress + "%";
|
||||
}
|
||||
|
||||
function ajaxRequest() {
|
||||
|
|
|
@ -7,7 +7,15 @@
|
|||
{% load staticfiles %}
|
||||
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||
<link href="{% static 'images/favicon.ico' %}" rel="shortcut icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title>{{ settings.title }}</title>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
|
||||
|
||||
<!-- Optional theme -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
@ -7,19 +7,33 @@
|
|||
{% load staticfiles %}
|
||||
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||
<link href="{% static 'images/favicon.ico' %}" rel="shortcut icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title>{{ settings.title }}</title>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
|
||||
|
||||
<!-- Optional theme -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<img src="{{ settings.logo }}" class="mainLogo">
|
||||
<h1>{{ settings.title }}</h1>
|
||||
<p>{{ settings.message_welcome_user }}</p>
|
||||
<div class="progress">
|
||||
<div id="progressbar" class="progress-bar progress-bar-striped" role="progressbar" style="width: {{ progress }}%">
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="margin50" ></div>
|
||||
|
||||
{% for question, options in questions_options.items %}
|
||||
<div class="container question" name="question" id="question_{{ question.id }}">
|
||||
<h2>{{ question.id }}: {{ question.title }}</h2>
|
||||
<p>{{ question.text }}</p>
|
||||
|
||||
|
@ -27,19 +41,28 @@
|
|||
{{ settings.message_already_answered }}
|
||||
</p>
|
||||
|
||||
<form action="#">
|
||||
{% for option in options %}
|
||||
|
||||
<ul class="list-group ">
|
||||
{% for option in options %}
|
||||
<li name="checkbox_div_{{ question.id }}" class="list-group-item">
|
||||
<label>
|
||||
<input name="checkbox_{{ question.id }}" type="checkbox" value="{{ option.id }}">
|
||||
{{ option.text }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
<button class="margin10" type="button" id="showSolution_{{ question.id }}" onmousedown="get_answer({{ question.id }})">{{ settings.button_solution }}</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<p id="explanation_{{ question.id }}" class="hide">{{ question.explanation }}</p>
|
||||
<div class="margin25"></div>
|
||||
<div class="container">
|
||||
<button class="btn btn-default show" type="button" id="showSolution_{{ question.id }}" onmouseup="get_answer({{ question.id }})">{{ settings.text_solution }}</button>
|
||||
<button class="btn btn-default hide" type="button" id="next_{{ question.id }}" onmouseup="scrollToNextQuestion({{ question.id }})">{{ settings.text_next }}</button>
|
||||
</div>
|
||||
|
||||
<div class="margin10 well well-sm hide" id="explanation_{{ question.id }}">
|
||||
<h3>{{ settings.text_answer }}</h3>
|
||||
<p>{{ question.explanation }}</p>
|
||||
</div>
|
||||
<div class="margin75"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="margin50" ></div>
|
||||
|
|
|
@ -7,7 +7,15 @@
|
|||
{% load staticfiles %}
|
||||
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||
<link href="{% static 'images/favicon.ico' %}" rel="shortcut icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title>{{ settings.title }}</title>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
|
||||
|
||||
<!-- Optional theme -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -20,7 +28,7 @@
|
|||
<div class="margin50" ></div>
|
||||
|
||||
<h2>Users</h2>
|
||||
<table>
|
||||
<table class="table">
|
||||
<tr class="table_headline">
|
||||
<td>name</td>
|
||||
<td>questions answered</td>
|
||||
|
@ -38,7 +46,7 @@
|
|||
<div class="margin50" ></div>
|
||||
|
||||
<h2>Questions</h2>
|
||||
<table>
|
||||
<table class="table">
|
||||
<tr class="table_headline">
|
||||
<td>title</td>
|
||||
<td>answers</td>
|
||||
|
@ -57,7 +65,10 @@
|
|||
|
||||
<div class="margin50" ></div>
|
||||
<hr/>
|
||||
{{ settings.footer }}
|
||||
<div class="container footer">
|
||||
{{ settings.footer }}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import datetime
|
||||
import json
|
||||
from __future__ import division
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render_to_response
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from tkupek_elearning.elearning.models import Setting, Question, Option, UserAnswer, User, UserAnswerOptions
|
||||
|
||||
|
@ -10,6 +11,13 @@ from tkupek_elearning.elearning.models import Setting, Question, Option, UserAns
|
|||
import pdb
|
||||
|
||||
|
||||
def get_progress(user):
|
||||
progress_max = Question.objects.all().count()
|
||||
progress_current = UserAnswer.objects.filter(user=user.id).count()
|
||||
progress = str(int(progress_current / progress_max * 100))
|
||||
return progress
|
||||
|
||||
|
||||
def start(request):
|
||||
|
||||
token = request.GET.get('token')
|
||||
|
@ -42,7 +50,9 @@ def start(request):
|
|||
questions_options[question] = options
|
||||
questions_options[question] = options
|
||||
|
||||
return render_to_response('elearning.html', {'settings': settings, 'questions_options': questions_options})
|
||||
progress = get_progress(user)
|
||||
|
||||
return render_to_response('elearning.html', {'settings': settings, 'questions_options': questions_options, 'progress': progress})
|
||||
|
||||
else:
|
||||
return render_to_response('access_denied.html', {'settings': settings})
|
||||
|
@ -95,7 +105,10 @@ def get_answer(request):
|
|||
user_answer_options.option = Option.objects.get(id=option)
|
||||
user_answer_options.save()
|
||||
|
||||
return HttpResponse(options_id)
|
||||
holder = {'options_id': options_id, 'progress': get_progress(user)}
|
||||
holder = json.dumps(holder)
|
||||
|
||||
return HttpResponse(holder)
|
||||
|
||||
|
||||
def get_user_answer(question, user):
|
||||
|
@ -124,6 +137,8 @@ def statistic(request):
|
|||
for question in questions:
|
||||
question.answers = UserAnswer.objects.filter(question=question.id).count()
|
||||
question.correct_answers = UserAnswer.objects.filter(question=question.id, correct=True).count()
|
||||
question.correct_answers_percentage = question.correct_answers / question.answers
|
||||
if question.answers:
|
||||
question.correct_answers_percentage = str(int(question.correct_answers / question.answers * 100))
|
||||
question.correct_answers_percentage += str(' %')
|
||||
|
||||
return render_to_response('statistic.html', {'settings': settings, 'users': users, 'questions': questions})
|
||||
|
|
Loading…
Reference in a new issue