summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--testapp/exam/forms.py12
-rw-r--r--testapp/exam/urls.py1
-rw-r--r--testapp/exam/views.py101
-rw-r--r--testapp/static/exam/css/base.css315
-rw-r--r--testapp/static/exam/css/question_paper_creation.css119
-rw-r--r--testapp/static/exam/js/bootstrap-modal.js260
-rw-r--r--testapp/static/exam/js/bootstrap-tabs.js80
-rw-r--r--testapp/static/exam/js/question_paper_creation.js237
-rw-r--r--testapp/templates/exam/ajax_marks.html4
-rw-r--r--testapp/templates/exam/ajax_questions.html31
-rw-r--r--testapp/templates/exam/design_questionpaper.html184
-rw-r--r--testapp/templates/exam/monitor.html4
12 files changed, 1327 insertions, 21 deletions
diff --git a/testapp/exam/forms.py b/testapp/exam/forms.py
index d0b0b74..9bfedbe 100644
--- a/testapp/exam/forms.py
+++ b/testapp/exam/forms.py
@@ -13,7 +13,7 @@ from string import letters, punctuation, digits
import datetime
languages = (
- ("select", "Select"),
+ ("select", "Select Language"),
("python", "Python"),
("bash", "Bash"),
("C", "C Language"),
@@ -23,7 +23,7 @@ languages = (
)
question_types = (
- ("select", "Select"),
+ ("select", "Select Question Type"),
("mcq", "Multiple Choice"),
("mcc", "Multiple Correct Choices"),
("code", "Code"),
@@ -207,3 +207,11 @@ class QuestionForm(forms.Form):
new_question.active = active
new_question.snippet = snippet
new_question.save()
+
+
+class RandomQuestionForm(forms.Form):
+ question_type = forms.CharField(max_length=8, widget=forms.Select\
+ (choices=question_types))
+ marks = forms.CharField(max_length=8, widget=forms.Select\
+ (choices=(('select', 'Select Marks'),)))
+ shuffle_questions = forms.BooleanField(required=False)
diff --git a/testapp/exam/urls.py b/testapp/exam/urls.py
index 33b2edf..3950a43 100644
--- a/testapp/exam/urls.py
+++ b/testapp/exam/urls.py
@@ -43,4 +43,5 @@ urlpatterns = patterns('exam.views',
url(r'^manage/designquestionpaper/manual$','manual_questionpaper'),
url(r'^manage/designquestionpaper/manual/(?P<questionpaper_id>\d+)/$',\
'manual_questionpaper'),
+ url(r'^ajax/questionpaper/(?P<query>.+)/$', 'ajax_questionpaper'),
)
diff --git a/testapp/exam/views.py b/testapp/exam/views.py
index 6c29107..2eb6dd4 100644
--- a/testapp/exam/views.py
+++ b/testapp/exam/views.py
@@ -11,12 +11,14 @@ from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.http import Http404
from django.db.models import Sum
+from django.views.decorators.csrf import csrf_exempt
from taggit.models import Tag
from itertools import chain
# Local imports.
-from exam.models import Quiz, Question, QuestionPaper
+from exam.models import Quiz, Question, QuestionPaper, QuestionSet
from exam.models import Profile, Answer, AnswerPaper, User
-from exam.forms import UserRegisterForm, UserLoginForm, QuizForm, QuestionForm
+from exam.forms import UserRegisterForm, UserLoginForm, QuizForm,\
+ QuestionForm, RandomQuestionForm
from exam.xmlrpc_clients import code_server
from settings import URL_ROOT
@@ -197,11 +199,11 @@ def results_user(request):
papers = AnswerPaper.objects.filter(user=user)
quiz_marks = []
for paper in papers:
- marks_obtained = paper.update_marks_obtained()
+ marks_obtained = paper.marks_obtained
max_marks = paper.question_paper.total_marks
percentage = round((marks_obtained/max_marks)*100, 2)
temp = paper.question_paper.quiz.description, marks_obtained,\
- max_marks, percentage
+ max_marks, percetage
quiz_marks.append(temp)
context = {'papers': quiz_marks}
return my_render_to_response("exam/results_user.html", context)
@@ -249,6 +251,7 @@ def edit_question(request):
options = request.POST.getlist('options')
type = request.POST.getlist('type')
active = request.POST.getlist('active')
+ language = request.POST.getlist('language')
snippet = request.POST.getlist('snippet')
for j, question_id in enumerate(question_list):
question = Question.objects.get(id=question_id)
@@ -258,6 +261,7 @@ def edit_question(request):
question.test = test[j]
question.options = options[j]
question.active = active[j]
+ question.language = language[j]
question.snippet = snippet[j]
question.type = type[j]
question.save()
@@ -292,6 +296,7 @@ def add_question(request, question_id=None):
d.options = form['options'].data
d.type = form['type'].data
d.active = form['active'].data
+ d.language = form['language'].data
d.snippet = form['snippet'].data
d.save()
question = Question.objects.get(id=question_id)
@@ -322,6 +327,7 @@ def add_question(request, question_id=None):
form.initial['options'] = d.options
form.initial['type'] = d.type
form.initial['active'] = d.active
+ form.initial['language'] = d.language
form.initial['snippet'] = d.snippet
form_tags = d.tags.all()
form_tags_split = form_tags.values('name')
@@ -389,15 +395,6 @@ def add_quiz(request, quiz_id=None):
context_instance=ci)
-def design_questionpaper(request, questionpaper_id=None):
- user = request.user
- ci = RequestContext(request)
- if not user.is_authenticated() or not is_moderator(user):
- raise Http404('You are not allowed to view this page!')
- return my_render_to_response('exam/add_questionpaper.html', {},
- context_instance=ci)
-
-
def show_all_questionpapers(request, questionpaper_id=None):
user = request.user
ci = RequestContext(request)
@@ -842,7 +839,11 @@ def complete(request, reason=None, questionpaper_id=None):
else:
q_paper = QuestionPaper.objects.get(id=questionpaper_id)
paper = AnswerPaper.objects.get(user=user, question_paper=q_paper)
- obt_marks = paper.update_marks_obtained()
+ paper.update_marks_obtained()
+ paper.update_percent()
+ paper.update_passed()
+ paper.save()
+ obt_marks = paper.marks_obtained
tot_marks = paper.question_paper.total_marks
if obt_marks == paper.question_paper.total_marks:
context = {'message': "Hurray ! You did an excellent job.\
@@ -1029,6 +1030,7 @@ def show_all_questions(request):
form.initial['options'] = d.options
form.initial['type'] = d.type
form.initial['active'] = d.active
+ form.initial['language'] = d.language
form.initial['snippet'] = d.snippet
form_tags = d.tags.all()
form_tags_split = form_tags.values('name')
@@ -1094,3 +1096,74 @@ def grade_user(request, username):
context = {'data': data}
return my_render_to_response('exam/grade_user.html', context,
context_instance=ci)
+
+
+@csrf_exempt
+def ajax_questionpaper(request, query):
+ """
+ During question paper creation, ajax call made to get question details.
+ """
+ if query == 'marks':
+ question_type = request.POST.get('question_type')
+ questions = Question.objects.filter(type=question_type)
+ marks = questions.values_list('points').distinct()
+ return my_render_to_response('exam/ajax_marks.html', {'marks': marks})
+ elif query == 'questions':
+ question_type = request.POST['question_type']
+ marks_selected = request.POST['marks']
+ fixed_questions = request.POST.getlist('fixed_list[]')
+ fixed_question_list = ",".join(fixed_questions).split(',')
+ random_questions = request.POST.getlist('random_list[]')
+ random_question_list = ",".join(random_questions).split(',')
+ question_list = fixed_question_list + random_question_list
+ questions = list(Question.objects.filter(type=question_type,
+ points=marks_selected))
+ questions = [ question for question in questions \
+ if not str(question.id) in question_list ]
+ return my_render_to_response('exam/ajax_questions.html',
+ {'questions': questions})
+
+
+def design_questionpaper(request):
+ user = request.user
+ ci = RequestContext(request)
+
+ if not user.is_authenticated() or not is_moderator(user):
+ raise Http404('You are not allowed to view this page!')
+
+ if request.method == 'POST':
+ fixed_questions = request.POST.getlist('fixed')
+ random_questions = request.POST.getlist('random')
+ random_number = request.POST.getlist('number')
+ is_shuffle = request.POST.get('shuffle_questions', False)
+ if is_shuffle == 'on':
+ is_shuffle = True
+
+ question_paper = QuestionPaper(shuffle_questions=is_shuffle)
+ quiz = Quiz.objects.order_by("-id")[0]
+ tot_marks = 0
+ question_paper.quiz = quiz
+ question_paper.total_marks = tot_marks
+ question_paper.save()
+ if fixed_questions:
+ fixed_questions_ids = ",".join(fixed_questions)
+ fixed_questions_ids_list = fixed_questions_ids.split(',')
+ for question_id in fixed_questions_ids_list:
+ question_paper.fixed_questions.add(question_id)
+ if random_questions:
+ for random_question, num in zip(random_questions, random_number):
+ question = Question.objects.get(id=random_question[0])
+ marks = question.points
+ question_set = QuestionSet(marks=marks, num_questions=num)
+ question_set.save()
+ for question_id in random_question.split(','):
+ question_set.questions.add(question_id)
+ question_paper.random_questions.add(question_set)
+ question_paper.update_total_marks()
+ question_paper.save()
+ return my_redirect('/exam/manage/showquiz')
+ else:
+ form = RandomQuestionForm()
+ context = {'form': form}
+ return my_render_to_response('exam/design_questionpaper.html',
+ context, context_instance=ci)
diff --git a/testapp/static/exam/css/base.css b/testapp/static/exam/css/base.css
index c822f4d..d3a0a0a 100644
--- a/testapp/static/exam/css/base.css
+++ b/testapp/static/exam/css/base.css
@@ -295,7 +295,7 @@ a:hover {
width: 160px;
}
.span4 {
- min-height : 500px;
+/* min-height : 500px; */
width: 220px;
}
.span5 {
@@ -1898,7 +1898,7 @@ button.btn::-moz-focus-inner, input[type=submit].btn::-moz-focus-inner {
padding: 0;
border: 0;
}
-.close {
+/*.close {
float: right;
color: #000000;
font-size: 20px;
@@ -1917,7 +1917,7 @@ button.btn::-moz-focus-inner, input[type=submit].btn::-moz-focus-inner {
-khtml-opacity: 0.4;
-moz-opacity: 0.4;
opacity: 0.4;
-}
+}*/
.alert-message {
position: relative;
padding: 7px 15px;
@@ -2045,4 +2045,313 @@ button.btn::-moz-focus-inner, input[type=submit].btn::-moz-focus-inner {
.label.notice {
background-color: #62cffc;
}
+.well {
+ background-color: #f5f5f5;
+ margin-bottom: 20px;
+ padding: 19px;
+ min-height: 20px;
+ border: 1px solid #eee;
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.well blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+.modal-backdrop {
+ background-color: #000000;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 10000;
+}
+.modal-backdrop.fade {
+ opacity: 0;
+}
+.modal-backdrop, .modal-backdrop.fade.in {
+ filter: alpha(opacity=80);
+ -khtml-opacity: 0.8;
+ -moz-opacity: 0.8;
+ opacity: 0.8;
+}
+/*
+.modal {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ z-index: 11000;
+ width: 560px;
+ margin: -250px 0 0 -280px;
+ background-color: #ffffff;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ *border: 1px solid #999;
+
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+}
+.modal .close {
+ margin-top: 7px;
+}
+.modal.fade {
+ -webkit-transform-style: preserve-3d;
+ -webkit-transition: opacity .3s linear, top .3s ease-out;
+ -moz-transition: opacity .3s linear, top .3s ease-out;
+ -ms-transition: opacity .3s linear, top .3s ease-out;
+ -o-transition: opacity .3s linear, top .3s ease-out;
+ transition: opacity .3s linear, top .3s ease-out;
+ top: -25%;
+}
+.modal.fade.in {
+ top: 50%;
+}
+.modal-header {
+ border-bottom: 1px solid #eee;
+ padding: 5px 15px;
+}
+.modal-body {
+ padding: 15px;
+}
+.modal-body form {
+ margin-bottom: 0;
+}
+.modal-footer {
+ background-color: #f5f5f5;
+ padding: 14px 15px 15px;
+ border-top: 1px solid #ddd;
+ -webkit-border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
+ -webkit-box-shadow: inset 0 1px 0 #ffffff;
+ -moz-box-shadow: inset 0 1px 0 #ffffff;
+ box-shadow: inset 0 1px 0 #ffffff;
+ zoom: 1;
+ margin-bottom: 0;
+}
+.modal-footer:before, .modal-footer:after {
+ display: table;
+ content: "";
+ zoom: 1;
+}
+.modal-footer:after {
+ clear: both;
+}
+.modal-footer .btn {
+ float: right;
+ margin-left: 5px;
+}
+.modal .popover, .modal .twipsy {
+ z-index: 12000;
+}
+*/
+.modal {
+ position: fixed;
+ top: 10%;
+ left: 50%;
+ z-index: 1050;
+ width: 560px;
+ margin-left: -280px;
+ background-color: #ffffff;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ *border: 1px solid #999;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ outline: none;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+}
+.modal.fade {
+ top: -25%;
+ -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;
+ -moz-transition: opacity 0.3s linear, top 0.3s ease-out;
+ -o-transition: opacity 0.3s linear, top 0.3s ease-out;
+ transition: opacity 0.3s linear, top 0.3s ease-out;
+}
+
+.modal.fade.in {
+ top: 10%;
+}
+
+.modal-header {
+ padding: 9px 15px;
+ border-bottom: 1px solid #eee;
+}
+
+.modal-header .close {
+ margin-top: 2px;
+}
+
+.modal-header h3 {
+ margin: 0;
+ line-height: 30px;
+}
+
+.modal-body {
+ position: relative;
+ max-height: 400px;
+ padding: 15px;
+ overflow-y: auto;
+}
+
+.modal-form {
+ margin-bottom: 0;
+}
+
+.modal-footer {
+ padding: 14px 15px 15px;
+ margin-bottom: 0;
+ text-align: right;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ -webkit-border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
+ *zoom: 1;
+ -webkit-box-shadow: inset 0 1px 0 #ffffff;
+ -moz-box-shadow: inset 0 1px 0 #ffffff;
+ box-shadow: inset 0 1px 0 #ffffff;
+}
+
+.modal-footer:before,
+.modal-footer:after {
+ display: table;
+ line-height: 0;
+ content: "";
+}
+
+.modal-footer:after {
+ clear: both;
+}
+.modal-footer .btn + .btn {
+ margin-bottom: 0;
+ margin-left: 5px;
+}
+
+.modal-footer .btn-group .btn + .btn {
+ margin-left: -1px;
+}
+
+.modal-footer .btn-block + .btn-block {
+ margin-left: 0;
+}
+.tabs, .pills {
+ margin: 0 0 18px;
+ padding: 0;
+ list-style: none;
+ zoom: 1;
+}
+.tabs:before,
+.pills:before,
+.tabs:after,
+.pills:after {
+ display: table;
+ content: "";
+ zoom: 1;
+}
+.tabs:after, .pills:after {
+ clear: both;
+}
+.tabs > li, .pills > li {
+ float: left;
+}
+.tabs > li > a, .pills > li > a {
+ display: block;
+}
+.tabs {
+ border-color: #ddd;
+ border-style: solid;
+ border-width: 0 0 1px;
+}
+.tabs > li {
+ position: relative;
+ margin-bottom: -1px;
+}
+.tabs > li > a {
+ padding: 0 15px;
+ margin-right: 2px;
+ line-height: 23px;
+ border: 1px solid transparent;
+ -webkit-border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+.tabs > li > a:hover {
+ text-decoration: none;
+ background-color: #eee;
+ border-color: #eee #eee #ddd;
+}
+.tabs .active > a, .tabs .active > a:hover {
+ color: #808080;
+ background-color: #ffffff;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+ cursor: default;
+}
+.tabs .menu-dropdown, .tabs .dropdown-menu {
+ top: 35px;
+ border-width: 1px;
+ -webkit-border-radius: 0 6px 6px 6px;
+ -moz-border-radius: 0 6px 6px 6px;
+ border-radius: 0 6px 6px 6px;
+}
+.tabs a.menu:after, .tabs .dropdown-toggle:after {
+ border-top-color: #999;
+ margin-top: 15px;
+ margin-left: 5px;
+}
+.tabs li.open.menu .menu, .tabs .open.dropdown .dropdown-toggle {
+ border-color: #999;
+}
+.tabs li.open a.menu:after, .tabs .dropdown.open .dropdown-toggle:after {
+ border-top-color: #555;
+}
+.pills a {
+ margin: 5px 3px 5px 0;
+ padding: 0 15px;
+ line-height: 30px;
+ text-shadow: 0 1px 1px #ffffff;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+}
+.pills a:hover {
+ color: #ffffff;
+ text-decoration: none;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
+ background-color: #00438a;
+}
+.pills .active a {
+ color: #ffffff;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
+ background-color: #0069d6;
+}
+.pills-vertical > li {
+ float: none;
+}
+.tab-content > .tab-pane, .pill-content > .pill-pane {
+ display: none;
+}
+.tab-content > .active, .pill-content > .active {
+ display: block;
+}
diff --git a/testapp/static/exam/css/question_paper_creation.css b/testapp/static/exam/css/question_paper_creation.css
new file mode 100644
index 0000000..c915320
--- /dev/null
+++ b/testapp/static/exam/css/question_paper_creation.css
@@ -0,0 +1,119 @@
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ font-weight: normal;
+ line-height: 18px;
+ color: #404040;
+}
+.clearfix {
+ clear: both;
+}
+.tabs li {
+ text-align: center;
+ width: 33%;
+}
+.tabs li:last-child {
+ width: 34%;
+}
+.tabs > .active > a {
+ border: 0;
+ background: lightgreen;
+}
+.tabs > .active > a:hover {
+ border: 0;
+ background: green;
+ color: #ffffff;
+}
+.tabs li a {
+ border-radius: 0;
+ margin-right: 0;
+}
+.tabs {
+ border: 1px solid #ddd;
+}
+#progress {
+ background: red;
+}
+#content-left{
+ text-align: center;
+ background: grey;
+}
+#content-right{
+ text-align: center;
+ background: grey;
+}
+#selectors {
+ margin-left: 0;
+ background: #fafafa;
+ padding: 7px 0;
+ border: 2px solid #f5f5f5;
+}
+#selectors .span4 {
+ margin-left: 0;
+}
+#id_question_type {
+ width: 100%;
+}
+#id_marks {
+ width: 100%;
+}
+#fixed-questions .span7 > div,
+#random-questions .span7 > div{
+ background: #f5f5f5;
+ height: 200px;
+ border: 1px solid #333333;
+ padding: 5px;
+}
+#fixed-available,
+#random-available {
+ height: 125px;
+ min-height: 125px;
+ overflow-y: scroll;
+ margin-bottom: 15px;
+}
+#fixed-added,
+#random-added {
+ height: 160px;
+ overflow-y: scroll;
+}
+#fixed-added hr,
+#random-added hr {
+ margin: 5px 0 4px;
+}
+.qcard {
+ position: relative;
+ background: #ffffff;
+ padding: 5px;
+ margin: 5px 5px;
+ box-shadow: 1px 1px 5px #cccccc;
+ -webkit-box-shadow: 1px 1px 5px #cccccc;
+ -moz-box-shadow: 1px 1px 5px #cccccc;
+ -o-box-shadow: 1px 1px 5px #cccccc;
+}
+.qcard ul {
+ margin-bottom: 5px;
+}
+.qcard .remove {
+ position: absolute;
+
+ top: 3px;
+ right: 3px;
+ padding: 1px 3px;
+ text-decoration: none;
+ color: #ffffff;
+ background: #ff4136;
+ border-radius: 3px;
+ font-weight: bold;
+}
+.qcard .remove:hover {
+ background: #333333;
+}
+.red-alert {
+ border: 2px solid red;
+}
+#myModal .qcard .remove{
+ display: none;
+}
+.well{
+ padding: 5px;
+}
diff --git a/testapp/static/exam/js/bootstrap-modal.js b/testapp/static/exam/js/bootstrap-modal.js
new file mode 100644
index 0000000..b328217
--- /dev/null
+++ b/testapp/static/exam/js/bootstrap-modal.js
@@ -0,0 +1,260 @@
+/* =========================================================
+ * bootstrap-modal.js v1.4.0
+ * http://twitter.github.com/bootstrap/javascript.html#modal
+ * =========================================================
+ * Copyright 2011 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================= */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
+ * ======================================================= */
+
+ var transitionEnd
+
+ $(document).ready(function () {
+
+ $.support.transition = (function () {
+ var thisBody = document.body || document.documentElement
+ , thisStyle = thisBody.style
+ , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
+ return support
+ })()
+
+ // set CSS transition event type
+ if ( $.support.transition ) {
+ transitionEnd = "TransitionEnd"
+ if ( $.browser.webkit ) {
+ transitionEnd = "webkitTransitionEnd"
+ } else if ( $.browser.mozilla ) {
+ transitionEnd = "transitionend"
+ } else if ( $.browser.opera ) {
+ transitionEnd = "oTransitionEnd"
+ }
+ }
+
+ })
+
+
+ /* MODAL PUBLIC CLASS DEFINITION
+ * ============================= */
+
+ var Modal = function ( content, options ) {
+ this.settings = $.extend({}, $.fn.modal.defaults, options)
+ this.$element = $(content)
+ .delegate('.close', 'click.modal', $.proxy(this.hide, this))
+
+ if ( this.settings.show ) {
+ this.show()
+ }
+
+ return this
+ }
+
+ Modal.prototype = {
+
+ toggle: function () {
+ return this[!this.isShown ? 'show' : 'hide']()
+ }
+
+ , show: function () {
+ var that = this
+ this.isShown = true
+ this.$element.trigger('show')
+
+ escape.call(this)
+ backdrop.call(this, function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ that.$element
+ .appendTo(document.body)
+ .show()
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element.addClass('in')
+
+ transition ?
+ that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) :
+ that.$element.trigger('shown')
+
+ })
+
+ return this
+ }
+
+ , hide: function (e) {
+ e && e.preventDefault()
+
+ if ( !this.isShown ) {
+ return this
+ }
+
+ var that = this
+ this.isShown = false
+
+ escape.call(this)
+
+ this.$element
+ .trigger('hide')
+ .removeClass('in')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ hideWithTransition.call(this) :
+ hideModal.call(this)
+
+ return this
+ }
+
+ }
+
+
+ /* MODAL PRIVATE METHODS
+ * ===================== */
+
+ function hideWithTransition() {
+ // firefox drops transitionEnd events :{o
+ var that = this
+ , timeout = setTimeout(function () {
+ that.$element.unbind(transitionEnd)
+ hideModal.call(that)
+ }, 500)
+
+ this.$element.one(transitionEnd, function () {
+ clearTimeout(timeout)
+ hideModal.call(that)
+ })
+ }
+
+ function hideModal (that) {
+ this.$element
+ .hide()
+ .trigger('hidden')
+
+ backdrop.call(this)
+ }
+
+ function backdrop ( callback ) {
+ var that = this
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
+ if ( this.isShown && this.settings.backdrop ) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+ .appendTo(document.body)
+
+ if ( this.settings.backdrop != 'static' ) {
+ this.$backdrop.click($.proxy(this.hide, this))
+ }
+
+ if ( doAnimate ) {
+ this.$backdrop[0].offsetWidth // force reflow
+ }
+
+ this.$backdrop.addClass('in')
+
+ doAnimate ?
+ this.$backdrop.one(transitionEnd, callback) :
+ callback()
+
+ } else if ( !this.isShown && this.$backdrop ) {
+ this.$backdrop.removeClass('in')
+
+ $.support.transition && this.$element.hasClass('fade')?
+ this.$backdrop.one(transitionEnd, $.proxy(removeBackdrop, this)) :
+ removeBackdrop.call(this)
+
+ } else if ( callback ) {
+ callback()
+ }
+ }
+
+ function removeBackdrop() {
+ this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ function escape() {
+ var that = this
+ if ( this.isShown && this.settings.keyboard ) {
+ $(document).bind('keyup.modal', function ( e ) {
+ if ( e.which == 27 ) {
+ that.hide()
+ }
+ })
+ } else if ( !this.isShown ) {
+ $(document).unbind('keyup.modal')
+ }
+ }
+
+
+ /* MODAL PLUGIN DEFINITION
+ * ======================= */
+
+ $.fn.modal = function ( options ) {
+ var modal = this.data('modal')
+
+ if (!modal) {
+
+ if (typeof options == 'string') {
+ options = {
+ show: /show|toggle/.test(options)
+ }
+ }
+
+ return this.each(function () {
+ $(this).data('modal', new Modal(this, options))
+ })
+ }
+
+ if ( options === true ) {
+ return modal
+ }
+
+ if ( typeof options == 'string' ) {
+ modal[options]()
+ } else if ( modal ) {
+ modal.toggle()
+ }
+
+ return this
+ }
+
+ $.fn.modal.Modal = Modal
+
+ $.fn.modal.defaults = {
+ backdrop: false
+ , keyboard: false
+ , show: false
+ }
+
+
+ /* MODAL DATA- IMPLEMENTATION
+ * ========================== */
+
+ $(document).ready(function () {
+ $('body').delegate('[data-controls-modal]', 'click', function (e) {
+ e.preventDefault()
+ var $this = $(this).data('show', true)
+ $('#' + $this.attr('data-controls-modal')).modal( $this.data() )
+ })
+ })
+
+}( window.jQuery || window.ender );
diff --git a/testapp/static/exam/js/bootstrap-tabs.js b/testapp/static/exam/js/bootstrap-tabs.js
new file mode 100644
index 0000000..a3c7ee1
--- /dev/null
+++ b/testapp/static/exam/js/bootstrap-tabs.js
@@ -0,0 +1,80 @@
+/* ========================================================
+ * bootstrap-tabs.js v1.4.0
+ * http://twitter.github.com/bootstrap/javascript.html#tabs
+ * ========================================================
+ * Copyright 2011 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================== */
+
+
+!function( $ ){
+
+ "use strict"
+
+ function activate ( element, container ) {
+ container
+ .find('> .active')
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+
+ element.addClass('active')
+
+ if ( element.parent('.dropdown-menu') ) {
+ element.closest('li.dropdown').addClass('active')
+ }
+ }
+
+ function tab( e ) {
+ var $this = $(this)
+ , $ul = $this.closest('ul:not(.dropdown-menu)')
+ , href = $this.attr('href')
+ , previous
+ , $href
+
+ if ( /^#\w+/.test(href) ) {
+ e.preventDefault()
+
+ if ( $this.parent('li').hasClass('active') ) {
+ return
+ }
+
+ previous = $ul.find('.active a').last()[0]
+ $href = $(href)
+
+ activate($this.parent('li'), $ul)
+ activate($href, $href.parent())
+
+ $this.trigger({
+ type: 'change'
+ , relatedTarget: previous
+ })
+ }
+ }
+
+
+ /* TABS/PILLS PLUGIN DEFINITION
+ * ============================ */
+
+ $.fn.tabs = $.fn.pills = function ( selector ) {
+ return this.each(function () {
+ $(this).delegate(selector || '.tabs li > a, .pills > li > a', 'click', tab)
+ })
+ }
+
+ $(document).ready(function () {
+ $('body').tabs('ul[data-tabs] li > a, ul[data-pills] > li > a')
+ })
+
+}( window.jQuery || window.ender );
diff --git a/testapp/static/exam/js/question_paper_creation.js b/testapp/static/exam/js/question_paper_creation.js
new file mode 100644
index 0000000..a144540
--- /dev/null
+++ b/testapp/static/exam/js/question_paper_creation.js
@@ -0,0 +1,237 @@
+$(document).ready(function(){
+ /* selectors for the 3 step tabs*/
+ $fixed_tab = $("#fixed-tab");
+ $random_tab = $("#random-tab");
+ $finish_tab = $("#finish-tab");
+
+ $question_type = $("#id_question_type");
+ $marks = $("#id_marks");
+
+ $total_marks = $("#total_marks");
+ /* ajax requsts on selectors change */
+ $question_type.change(function() {
+ $.ajax({
+ url: "/exam/ajax/questionpaper/marks/",
+ type: "POST",
+ data: {
+ question_type: $question_type.val()
+ },
+ dataType: "html",
+ success: function(output) {
+ $marks.html(output);
+ }
+ });
+ });
+
+ $marks.change(function() {
+ var fixed_question_list = [];
+ var fixed_inputs = $("input[name=fixed]");
+ var random_question_list = [];
+ var random_inputs = $("input[name=random]");
+ for(var i = 0; i < fixed_inputs.length; i++){
+ fixed_question_list.push($(fixed_inputs[i]).val());
+ }
+ for(var i = 0; i < random_inputs.length; i++){
+ random_question_list.push($(random_inputs[i]).val());
+ }
+ $.ajax({
+ url: "/exam/ajax/questionpaper/questions/",
+ type: "POST",
+ data: {
+ question_type: $question_type.val(),
+ marks: $marks.val(),
+ fixed_list: fixed_question_list,
+ random_list: random_question_list
+ },
+ dataType: "html",
+ success: function(output) {
+ if($fixed_tab.hasClass("active")) {
+ var questions = $(output).filter("#questions").html();
+ $("#fixed-available").html(questions);
+ } else if($random_tab.hasClass("active")) {
+ var questions = $(output).filter("#questions").html();
+ var numbers = $(output).filter("#num").html();
+ $("#random-available").html(questions);
+ $("#number-wrapper").html(numbers);
+ }
+ }
+ });
+ });
+
+ /* adding fixed questions */
+ $("#add-fixed").click(function(e) {
+ var count = 0;
+ var selected = [];
+ var html = "";
+ var $element;
+ var total_marks = parseFloat($total_marks.text());
+ var marks_per = parseFloat($marks.val())
+ $("#fixed-available input:checkbox").each(function(index, element) {
+ if($(this).attr("checked")) {
+ qid = $(this).attr("data-qid");
+ if(!$(this).hasClass("ignore")) {
+ selected.push(qid);
+ $element = $("<div class='qcard'></div>");
+ html += "<li>" + $(this).next().html() + "</li>";
+ count++;
+ }
+ }
+ });
+ html = "<ul>" + html + "</ul>";
+ selected = selected.join(",");
+ var $input = $("<input type='hidden'>");
+ $input.attr({
+ value: selected,
+ name: "fixed"
+ });
+ $remove = $("<a href='#' class='remove' data-num="+count+" data-marks = "+marks_per +">&times;</div>");
+ $element.html(count + " question(s) added").append(html).append($input).append($remove);
+ $("#fixed-added").prepend($element);
+ total_marks = total_marks + count * marks_per;
+ $total_marks.text(total_marks)
+ e.preventDefault();
+ });
+
+ /* adding random questions */
+ $("#add-random").click(function(e) {
+ $numbers = $("#numbers");
+ random_number = $numbers.val()
+ if($numbers.val()) {
+ $numbers.removeClass("red-alert");
+ var count = 0;
+ var selected = [];
+ var html = "";
+ var $element;
+ var total_marks = parseFloat($total_marks.text());
+ var marks_per = parseFloat($marks.val())
+ $("#random-available input:checkbox").each(function(index, element) {
+ if($(this).attr("checked")) {
+ qid = $(this).attr("data-qid");
+ if(!$(this).hasClass("ignore")) {
+ selected.push(qid);
+ $element = $("<div class='qcard'></div>");
+ html += "<li>" + $(this).next().html() + "</li>";
+ count++;
+ }
+ }
+ });
+ html = "<ul>" + html + "</ul>";
+ selected = selected.join(",");
+ var $input_random = $("<input type='hidden'>");
+ $input_random.attr({
+ value: selected,
+ name: "random"
+ });
+ var $input_number = $("<input type='hidden'>");
+ $input_number.attr({
+ value: $numbers.val(),
+ name: "number"
+ });
+ $remove = $("<a href='#' class='remove' data-num="+random_number+" data-marks = "+marks_per +">&times;</div>");
+ $element.html(random_number + " question(s) will be selected from " + count + " question(s)").append(html).append($input_random).append($input_number).append($remove);
+ $("#random-added").prepend($element);
+ total_marks = total_marks + random_number * marks_per;
+ $total_marks.text(total_marks)
+ } else {
+ $numbers.addClass("red-alert");
+ }
+ e.preventDefault();
+ });
+
+ /* removing added questions */
+ $(".qcard .remove").live("click", function(e) {
+ var marks_per = $(this).attr('data-marks');
+ var num_question = $(this).attr('data-num');
+ var sub_marks = marks_per*num_question;
+ var total_marks = parseFloat($total_marks.text());
+ total_marks = total_marks - sub_marks;
+ $total_marks.text(total_marks);
+
+ $(this).parent().slideUp("normal", function(){ $(this).remove(); });
+ e.preventDefault();
+ });
+
+ /* showing/hiding selectors on tab click */
+ $(".tabs li").click(function() {
+ if($(this).attr("id") == "finish-tab") {
+ $("#selectors").hide();
+ } else {
+ $question_type.val('select');
+ $marks.val('select')
+ $("#selectors").show();
+ }
+ });
+ /* check all questions on checked*/
+ $("#checkall").live("click", function(){
+ if($(this).attr("checked")) {
+ if($("#fixed-tab").hasClass("active")) {
+ $("#fixed-available input:checkbox").each(function(index, element) {
+ $(this).attr('checked','checked');
+ });
+ }
+ else {
+ $("#random-available input:checkbox").each(function(index, element) {
+ $(this).attr('checked','checked');
+ });
+ }
+ }
+ else {
+ if($("#fixed-tab").hasClass("active")) {
+ $("#fixed-available input:checkbox").each(function(index, element) {
+ $(this).removeAttr('checked');
+ });
+ }
+ else {
+ $("#random-available input:checkbox").each(function(index, element) {
+ $(this).removeAttr('checked');
+ });
+ }
+ }
+ });
+
+ /* show preview on preview click */
+ $("#preview").click(function(){
+ questions = getQuestions()
+ if(questions.trim() == ""){
+ $('#modal_body').html("No questions selected");
+ }
+ else {
+ $('#modal_body').html(questions);
+ }
+ $("#myModal").modal('show');
+ });
+
+ /* tab change on next or previous button click */
+ $("#fixed-next").click(function(){
+ $("#random").click();
+ });
+ $("#random-next").click(function(){
+ $("#finished").click();
+ });
+
+ $("#random-prev").click(function(){
+ $("#fixed").click();
+ });
+
+ $("#finish-prev").click(function(){
+ $("#random").click();
+ });
+
+ /* Check at least one question is present before saving */
+ $('#save').click(function(){
+ questions = getQuestions();
+ if(questions.trim() == ""){
+ $("#modalSave").modal("show");
+ }
+ else {
+ document.forms["frm"].submit();
+ }
+ });
+
+ /* Fetch selected questions */
+ function getQuestions(){
+ var fixed_div = $("#fixed-added").html();
+ var random_div = $("#random-added").html();
+ return fixed_div+random_div;
+ }
+}); //document
diff --git a/testapp/templates/exam/ajax_marks.html b/testapp/templates/exam/ajax_marks.html
new file mode 100644
index 0000000..716bb88
--- /dev/null
+++ b/testapp/templates/exam/ajax_marks.html
@@ -0,0 +1,4 @@
+<option value='select'>Select Marks</option>
+{% for mark in marks %}
+<option value="{{ mark.0 }}"> {{ mark.0 }} </option>
+{% endfor %}
diff --git a/testapp/templates/exam/ajax_questions.html b/testapp/templates/exam/ajax_questions.html
new file mode 100644
index 0000000..e343f9b
--- /dev/null
+++ b/testapp/templates/exam/ajax_questions.html
@@ -0,0 +1,31 @@
+<div id="questions">
+ {% if questions %}
+ <input type="checkbox" id="checkall" class="ignore">
+ <span><b> <font size="3"> Select All </font></b></span>
+ {% endif %}
+ <ul class="inputs-list">
+
+ {% for question in questions %}
+ <li>
+ <label>
+ <input type="checkbox" name="questions" data-qid="{{question.id}}">
+ <span> {{ question.summary }} </span>
+ </label>
+ </li>
+ {% endfor %}
+ </ul>
+</div>
+
+<div id="num">
+ <select id="numbers">
+ <option value="">Number of questions to be picked from the pool</option>
+ {% for q in questions %}
+ {% if forloop.counter0 != 0 %}
+ <option value={{forloop.counter0}}>{{ forloop.counter0}}</option>
+ {% endif %}
+ {% if questions|length == 1%}
+ <option value=1>1</option>
+ {% endif %}
+ {% endfor %}
+ </select>
+</div>
diff --git a/testapp/templates/exam/design_questionpaper.html b/testapp/templates/exam/design_questionpaper.html
new file mode 100644
index 0000000..8994148
--- /dev/null
+++ b/testapp/templates/exam/design_questionpaper.html
@@ -0,0 +1,184 @@
+{% extends "manage.html" %}
+
+{% block subtitle %}Design Question Paper{% endblock %}
+
+{% block css %}
+<link rel="stylesheet" href="{{ URL_ROOT }}/static/exam/css/base.css" type="text/css" />
+<link rel="stylesheet" href="{{ URL_ROOT }}/static/exam/css/question_quiz.css" type="text/css" />
+<link rel="stylesheet" media="all" type="text/css" href="{{ URL_ROOT }}/static/exam/css/autotaggit.css" />
+<link rel="stylesheet" media="all" type="text/css" href="{{ URL_ROOT }}/static/exam/css/question_paper_creation.css" />
+<style>
+select
+{
+ width:auto;
+}
+</style>
+{% endblock %}
+{% block script %}
+<script src="/static/taggit_autocomplete_modified/jquery.min.js" type="text/javascript"></script>
+<script src="/static/taggit_autocomplete_modified/jquery.autocomplete.js" type="text/javascript"></script>
+
+
+<script src="{{ URL_ROOT }}/static/exam/js/bootstrap-tabs.js"></script>
+<script src="{{ URL_ROOT }}/static/exam/js/add_questionpaper.js"></script>
+<script src="{{ URL_ROOT }}/static/exam/js/question_paper_creation.js"></script>
+<script src="{{ URL_ROOT }}/static/exam/js/bootstrap-modal.js"></script>
+{% endblock %}
+
+{% block manage %}
+<input type=hidden id="url_root" value={{ URL_ROOT }}>
+<center><b>Manual mode to design the {{lang}} Question Paper</center><br>
+ <ul class="tabs" data-tabs="tabs">
+ <li class="active" id="fixed-tab">
+ <a href="#fixed-questions" id="fixed">
+ STEP 1<br>
+ Add Fixed Questions
+ </a>
+ </li>
+ <li id="random-tab">
+ <a href="#random-questions" id="random">
+ STEP 2<br>
+ Add Random Questions
+ </a>
+ </li>
+ <li id="finish-tab">
+ <a href="#finish" id="finished">
+ STEP 3<br>
+ Finish
+ </a></li>
+</ul>
+
+<form action="{{URL_ROOT}}/exam/manage/designquestionpaper/" method="post" name=frm > {% csrf_token %}
+ <div>
+ <h3>Total Marks: <span id="total_marks" class="well">0</span></h3>
+ </div>
+<div class="tab-content">
+ <!-- common to fixed and random questions -->
+ <div class="row" id="selectors">
+ <h5 style="padding-left: 20px;">Please select Question type and Marks</h5>
+ <div class="span4">
+ {{ form.question_type }}
+ </div> <!-- /.span4 -->
+ <div class="span4">
+ {{ form.marks }}
+ </div> <!-- /.span4 -->
+ <div class="span4">
+ <div class="pull-left" id="number-wrapper"></div>
+ </div> <!-- /.span4 -->
+ </div> <!-- /.row -->
+ <br><br>
+
+
+ <div class="tab-pane active" id="fixed-questions">
+ <div class="row">
+ <div class="span7">
+ <div id="fixed-available-wrapper">
+ <p><u>Select questions to add:</u></p>
+ <div id="fixed-available">
+ </div>
+ <a id="add-fixed" class="btn small primary pull-right" href="#">Add to paper</a>
+ </div>
+ </div>
+ <div class="span7">
+ <div id="fixed-added-wrapper">
+ <p><u>Fixed questions currently in paper:</u></p>
+ <div id="fixed-added">
+ </div>
+ </div>
+ </div>
+ </div> <!-- /.row -->
+ <br>
+ <div class="pull-right">
+ <a class="btn" id="fixed-next">Next &gt;</a>
+ </div>
+
+ </div> <!-- /#fixed-questions -->
+
+
+ <div class="tab-pane" id="random-questions">
+ <div class="row">
+ <div class="span7">
+ <div id="random-available-wrapper">
+ <p><u>Select questions to add to the pool:</u></p>
+ <div id="random-available">
+ </div>
+ <a id="add-random" class="btn small primary pull-right" href="#">Add to paper</a>
+ </div>
+ </div>
+ <div class="span7">
+ <div id="random-added-wrapper">
+ <p><u>Pool of questions currently in paper:</u></p>
+ <div id="random-added">
+ </div>
+ </div>
+ </div>
+ </div> <!-- /.row -->
+ <br>
+ <div class="pull-left">
+ <a class="btn" id="random-prev">&lt; Previous</a>
+ </div>
+ <div class="pull-right">
+ <a class="btn" id="random-next">Next &gt;</a>
+ </div>
+ </div> <!-- /#random-questions -->
+
+ <div class="tab-pane" id="finish">
+ <center>
+ <h5>Almost finished creating your question paper</h5>
+ <label style="float: none;">
+ {{ form.shuffle_questions }}
+ <span>Auto shuffle.</span>
+ </label> <br><br>
+ <input class ="btn primary large" type="button" id="preview" value="Preview question paper">
+ <input class ="btn primary large" type="button" id="save" value="Save question paper">
+ <br>
+ <div class="pull-left">
+ <a class="btn" id="finish-prev">&lt; Previous</a>
+ </div>
+ </center>
+ </div> <!-- /#finish -->
+</div>
+<!-- /.tab-content -->
+</form>
+<br>
+<div class="clearfix"></div>
+
+<!-- Modal -->
+<div class="modal fade " id="myModal" >
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myModalLabel">Question Paper Preview</h4>
+ </div>
+ <div id = "modal_body"class="modal-body">
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn primary close" data-dismiss="modal">OK</button>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="modal fade " id="modalSave" >
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myModalLabel">Cannot Save</h4>
+ </div>
+ <div id = "modal_body"class="modal-body">
+ Please select questions for your paper
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn primary close" data-dismiss="modal">OK</button>
+ </div>
+ </div>
+ </div>
+</div>
+</div>
+
+<script>
+ $(function () {
+ $('.tabs').tabs()
+ })
+</script>
+{% endblock %}
diff --git a/testapp/templates/exam/monitor.html b/testapp/templates/exam/monitor.html
index aa8b678..ecdb852 100644
--- a/testapp/templates/exam/monitor.html
+++ b/testapp/templates/exam/monitor.html
@@ -47,7 +47,7 @@
<th> Roll number </th>
<th> Institute </th>
<th> Questions answered </th>
- <th> Total marks </th>
+ <th> Marks obtained </th>
<th> Attempts </th>
</tr>
{% for paper in papers %}
@@ -57,7 +57,7 @@
<td> {{ paper.profile.roll_number }} </td>
<td> {{ paper.profile.institute }} </td>
<td> {{ paper.get_answered_str }} </td>
- <td> {{ paper.get_total_marks }} </td>
+ <td> {{ paper.marks_obtained }} </td>
<td> {{ paper.answers.count }} </td>
</tr>
{% endfor %}