diff --git a/ComSemApp/administrator/views.py b/ComSemApp/administrator/views.py index 8fa6f9f8..4542ba1d 100644 --- a/ComSemApp/administrator/views.py +++ b/ComSemApp/administrator/views.py @@ -8,7 +8,9 @@ from django.views.generic import ListView, CreateView, UpdateView, FormView, DeleteView from django.views import View from django.core.mail import send_mail +from django.core.validators import validate_email from django.contrib import messages +import re from django.contrib.auth.models import User from ComSemApp.models import * @@ -17,7 +19,6 @@ from ComSemApp.libs.mixins import RoleViewMixin - class AdminViewMixin(RoleViewMixin): role_class = Admin @@ -66,6 +67,104 @@ def _send_email(self, user, password): fail_silently=False, ) + def db_create_user(self, **kwargs): + user = User.objects.create(**kwargs) + password = User.objects.make_random_password() + user.set_password(password) + user.save() + self._send_email(user, password) + return user + + def db_create_student(self, **kwargs): + institution = self.insititution + user = self.db_create_user(**kwargs) + return Student.objects.create(user=user, institution=institution) + + #handle CSV upload + def post(self, request, *args, **kwargs): + if (len(request.FILES) > 0): #check to make sure file was uploaded + csv_file = request.FILES['file'] + file_data = csv_file.read().decode("utf-8") + lines = file_data.split("\n") + message_content = [""] + linecount = 0 + rejectcount = 0 + for line in lines: + if len(line): #make sure line isnt empty + fields = line.split(",") + okToCreate = True + rejected = False + linecount += 1 + if (fields[0] == "" or fields[0] == ""): + #end of file + break + if (len(fields) < 4): + message = "!!! Missing columns, please make sure you have columns as follows: firstname,lastname,email,username" + message_content.append(message) + rejected = True + rejectcount += 1 + break + if (fields[0].isalpha() == False or fields[1].isalpha() == False): + message = (str(linecount) + " " + fields[0] + " " + fields[1] + " " + fields[2] + " " + fields[3] + " Invalid First or Last Name \n") + message_content.append(message) + rejectcount += 1 + rejected = True + okToCreate = False + for user in Student.objects.filter(institution=self.institution): + if(user.user.email== fields[2]): + okToCreate = False + if (rejected == False): ##if rejected is false, we need to increment the number of rejects, if its already false, dont increment it but still log error + rejectcount += 1 + rejected = True + message = (str(linecount) + " " + fields[0] + " " + fields[1] + " " + fields[2] + " " + fields[3] + " Duplicate Email Address \n") + message_content.append(message) + + if(user.user.username== fields[3]): + okToCreate = False + if (rejected == False): ##if rejected is false, we need to increment the number of rejects, if its already false, dont increment it but still log error + rejectcount += 1 + rejected = True + message = (str(linecount) + " " + fields[0] + " " + fields[1] + " " + fields[2] + " " + fields[3] + " Duplicate Username \n") + message_content.append(message) + if(okToCreate == False): + break + + # Check if a valid email address + match = re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', fields[2].lower()) + + if (match == None): + if(rejected == False): + rejectcount += 1 + rejected = True + okToCreate = False + message = (str(linecount) + " " + fields[0] + " " + fields[1] + " " + fields[2] + " " + fields[3] + " Invalid Email Address \n") + message_content.append(message) + + # Check for valid username + usernameCheck = re.match('^[\w.@+-]+$', fields[3]) + if (usernameCheck == None): + if(rejected == False): + rejectcount += 1 + rejected = True + okToCreate = False + message = (str(linecount) + " " + fields[0] + " " + fields[1] + " " + fields[2] + " " + fields[3] + " Invalid Username \n") + message_content.append(message) + + if (okToCreate == True): + user = { + "first_name": fields[0], + "last_name": fields[1], + "email": fields[2], + "username": fields[3] + } + self.db_create_student(**user) + print("student made") + message_content.insert(0, ("" + str((linecount - rejectcount)) + "/" + str(linecount)+ " Accounts created sucessfully\n" + "The below users were not added, Their line numbers are listed to the left,\nLines with multiple errors will be listed multiple times \n \n")) + message_disp = "".join(message_content) + messages.add_message(request, messages.ERROR, message_disp) + request.FILES.pop('file', None) #delete the csv file from memory + return HttpResponseRedirect(self.success_url) + @atomic def _create_student(self, **kwargs): user = User.objects.create_user(**kwargs) @@ -134,11 +233,9 @@ def post(self, request): messages.add_message(request, messages.ERROR, message) return HttpResponseRedirect(self.success_url) - - def get_queryset(self): + def get_queryset(self): return Student.objects.filter(institution=self.institution) - class CourseListView(AdminViewMixin, ListView): model = Course template_name = 'ComSemApp/admin/course_list.html' diff --git a/ComSemApp/static/ComSemApp/DKNotus-Tour-master/DKNotusTour.png b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/DKNotusTour.png new file mode 100755 index 00000000..126344fe Binary files /dev/null and b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/DKNotusTour.png differ diff --git a/ComSemApp/static/ComSemApp/DKNotus-Tour-master/LICENSE b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/LICENSE new file mode 100755 index 00000000..5b132a5e --- /dev/null +++ b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 DK Notus IT Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ComSemApp/static/ComSemApp/DKNotus-Tour-master/README.md b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/README.md new file mode 100755 index 00000000..630e86e7 --- /dev/null +++ b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/README.md @@ -0,0 +1,235 @@ +# DK Notus Tour + +#### This compact solution for guided tours has 27 languages support. It requires only two very common dependencies: **jQuery** and **Bootstrap**. Also has useful features like auto scroll and "spotlight". We hope you enjoy it. + +![DK Notus Tour](DKNotusTour.png) + +We tried to keep all data regarding usage as short as possible. +## 1. Features + +Features that we considerble important: + + - **small requirements** - only jQuery and Bootstrap; + - **simple usage** - one function for common usage - yes, it's that simple; + - **events** - for advanced programmers usage; + - **scroll** - and some more useful features; + - **multi elements selection** - you can point more then one element for one tour step; + - **translations** - 27 languages support. + +## 2. Simple use case + +Lets start with two step tour for elements below: + +First of all we need to include two common libraries jQuery and Bootstrap. You ca use some CDN for that. + + + + +Then it's time tour library `dknotus-tour.js` or `dknotus-tour.min.js`. + + + +Finally we can define our own tour and run it with Tour.run(). Yes, it's that simple. + +```javascript + $(function(){ + $('#simpleBtn').click(function(){ + Tour.run([ + { + element: $('#btn1'), + content: 'first btn' + }, + { + element: $('#btn2'), + content: 'and the second one
description might be HTML' + }, + ]); + }); + }); +``` + +## 3. Different tour positions +```javascript + $(function(){ + $('#positionsBtn').click(function(){ + Tour.run([ + { + element: $('#posBtn'), + content: 'by default tour is on the right' + }, + { + element: $('#posBtn'), + content: 'but it can be on top', + position: 'top' + }, + { + element: $('#posBtn'), + content: 'bottom', + position: 'bottom' + }, + { + element: $('#posBtn'), + content: 'and finally on the left', + position: 'left' + } + ]); + }); + }); +``` + +## 4. Global and local parameters + +Tour may be run with two parameters: tour description (mandatory) and global options (optional) Tour.run(tourDescription, options). If for some tour hint some parameter is not set, then if it's possible it's taken from options. + +Possible parameters for hints descriptions and for global options: + +Parameter | Default value | Description +--------- | ------------- | ----------- +element | *none* | jQuery element (might be more then one), if it's not set then hint is skipped. +content | *empty string* | It's for contents of particular hints. +close | true | Defines if close button should be shown. +language | en | Defines interface language. Available languages: +|| en | English (default) +|| pl | Polish +|| be | Belarusian +|| ca | Catalan +|| cs | Czech +|| da | Danish +|| de | German +|| el | Greek +|| es | Spanish +|| et | Estonian +|| fi | Finnish +|| fr | French +|| hu | Hungarian +|| it | Italian +|| lt | Lithuanian +|| lv | Latvian +|| mk | Macedonian +|| nl | Dutch +|| no | Norwegian +|| pt | Portuguese +|| ru | Russian +|| sk | Slovak +|| sl | Slovenian +|| sq | Albanian +|| sv | Swedish +|| tr | Turkish +|| uk | Ukrainian +padding | 5 | Extra space around tour exposed elements. (Has only sense when spotlight option is true). +position | right | Determines where hint should be shown relatively to element it describes. +||| Possible values: right, left, top and bottom. +scroll | true | If true then scrolls window so selected element and hint would be as close as possible to the view center. +spotlight | true | If true then covers everything except selected element and hint with shadow. +forceCorrectionLeft | 0 | Useful if for some reason left offset needs to be modified. +forceCorrectionTop | 0 | Useful if for some reason top offset needs to be modified. +forceCorrectionWidth | 0 | Useful if for some reason width needs to be modified. +forceCorrectionHeight | 0 | Useful if for some reason height needs to be modified. + +All above options can be used for both: single hint description and for global options. With global options previous example can be written like: + +```javascript + $(function(){ + $('#positionsShorterBtn').click(function(){ + var globalOptions = { + element: $('#posBtn') + }; + + var tourDescription = [ + { + content: 'by default tour is on the right' + }, + { + content: 'but it can be on top', + position: 'top' + }, + { + content: 'bottom', + position: 'bottom' + }, + { + content: 'and finally on the left', + position: 'left' + } + ]; + + Tour.run(tourDescription, globalOptions); + }); + }); +``` + +## 5. Events example + +There are four events that can be used by developers: + + - **onstart()** - Triggered when new tour starts ( `Tour.run()` ); + - **onfinish()** - Triggered when Finish button is clicked; + - **onclose()** - Triggered when Close button is pressed ( `Tour.close()` ); + - **onstep( currentStep )** - Triggered on every step shown ( `Tour.next()` or `Tour.prev()` ); + - **onresize()** - By default this one is set. + +```javascript + $(function(){ + $('#eventsBtn').click(function(){ + Tour.onstart = function(){ + console.log('We started!'); + }; + + Tour.onfinish = function(){ + console.log('The End'); + }; + + Tour.onclose = function(){ + console.log('Tour interupted'); + }; + + Tour.onstep = function(currentStep){ + console.log('"That\'s one small step for a man ..."'); + console.log(currentStep); + }; + + Tour.run([ + { + element: $('#eventBtn1').add('#eventBtn3'), + content: 'You prefer photos?', + position: 'top' + }, + { + element: $('#eventBtn3').add('#eventBtn4'), + content: 'or videos?', + onstep: function(currentStep) { + console.log('Events defined in step, overwrites global definition'); + } + } + ]); + }); + }); +``` + +## 6. Tour interface + +#### Methods + +Method | Description +------ | ----------- +**Tour.run( tourDescription, globlOptions )** | Function for running Tour. +**Tour.next()** | Goes to next tour step. +**Tour.prev()** | Goes to previous tour step. +**Tour.close()** | Interrupts tour and closes it. +**Tour.current()** | Returns current step description. + +#### Events + +By default all except `onresize` are set to null. + +Event | Description +----- | ----------- +**Tour.onstart()** | Triggered when new tour starts ( Tour.run() ). +**Tour.onfinish()** | Triggered when Finish button is clicked. +**Tour.onclose()** | Triggered when Close button is pressed ( Tour.close() ). +**Tour.onstep( currentEvent )** | Triggered on every step shown ( Tour.next() or Tour.prev() ). +**Tour.onresize()** | By default this one is set. + +## 7. Contact + +Jan Doleczek diff --git a/ComSemApp/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.js b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.js new file mode 100755 index 00000000..d1d25fd5 --- /dev/null +++ b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.js @@ -0,0 +1,391 @@ +/*! + * DK Notus Tour JavaScript Library v1.2 + * https://github.com/DKNotusIT/DKNotus-Tour/ + * + * Copyright DK Notus and other contributors + * Released under the MIT license + * https://github.com/DKNotusIT/DKNotus-Tour/blob/master/LICENSE + * + * Date: 2018-03-17 + */ + +var Tour = (function() { + var t = [], + o, cur + T = { + step: { + pl: "krok", + en: "step", + be: "крок", + ca: "pas", + cs: "krok", + da: "trin", + de: "Schritt", + el: "βήμα", + es: "paso", + et: "samm", + fi: "vaihe", + fr: "étape", + hu: "lépés", + it: "passo", + lt: "žingsnis", + lv: "solis", + mk: "чекор", + nl: "stap", + no: "trinn", + pt: "passo", + ru: "шаг", + sk: "krok", + sl: "korak", + sq: "hapi", + sv: "steg", + tr: "adım", + uk: "крок" + }, + Next: { + pl: "Następny", + en: "Next", + be: "Далей", + ca: "Següent", + cs: "Další", + da: "Næste", + de: "Weiter", + el: "Την επόμενη", + es: "Siguiente", + et: "Järgmine", + fi: "Seuraava", + fr: "Prochaine", + hu: "Következő", + it: "Accanto", + lt: "Kitas", + lv: "Nākamā", + mk: "Следна", + nl: "Volgende", + no: "Neste", + pt: "Próximo", + ru: "Далее", + sk: "Ďalej", + sl: "Naprej", + sq: "Tjetër", + sv: "Nästa", + tr: "Gelecek", + uk: "Далі" + }, + Previous: { + pl: "Poprzedni", + en: "Previous", + be: "Папярэдні", + ca: "Anteriors", + cs: "Předchozí", + da: "Tidligere", + de: "Vorherige", + el: "Προηγούμενο", + es: "Anterior", + et: "Eelmine", + fi: "Edellinen", + fr: "Précédente", + hu: "Előző", + it: "Precedente", + lt: "Ankstesnis", + lv: "Iepriekšējā", + mk: "Претходна", + nl: "Vorige", + no: "Tidligere", + pt: "Anterior", + ru: "Предыдущий", + sk: "Predchádzajúce", + sl: "Prejšnji", + sq: "E mëparshme", + sv: "Föregående", + tr: "Önceki", + uk: "Попередній" + }, + Finish: { + pl: "Zakończ", + en: "Finish", + be: "Аздабленне", + ca: "Acabat", + cs: "Dokončit", + da: "Finish", + de: "Finish", + el: "Τελειώνει", + es: "Acabado", + et: "Lõpeta", + fi: "Loppuun", + fr: "Finition", + hu: "Befejezés", + it: "Finitura", + lt: "Apdaila", + lv: "Apdare", + mk: "Заврши", + nl: "Afwerking", + no: "Ferdig", + pt: "Acabamento", + ru: "Отделка", + sk: "Povrch", + sl: "Zaključek", + sq: "Finish", + sv: "Avsluta", + tr: "Bitir", + uk: "Оздоблення" + } + }; + + function _t(s) { + return T[s][t[cur].language] || T[s]['en']; + } + + function step(n) { + cur = n; + $('.tourStep, .tourBg').remove(); + + if (!t[n]) { + return; + } + + $('body').append([ + '
', + '
', + '
', + !t[n].close ? '' : '', + '
', + t[n].content, + '
', + '', + '
', + '
' + ].join('')); + + var el = $('.tourStep') + .addClass(t[n].position) + .css({ + minWidth: 250 + }), + x = 0, + y = 0; + + if (t[n].element && !!t[n].element.length) { + var x1 = 1e6, + y1 = 1e6, + x2 = 0, + y2 = 0; + + t[n].element.each(function(k, v) { + var ofs = $(v).offset(); + x1 = Math.min(x1, ofs.left + t[n].forceCorrectionLeft); + y1 = Math.min(y1, ofs.top + t[n].forceCorrectionTop); + + x2 = Math.max(x2, ofs.left + t[n].forceCorrectionLeft + t[n].forceCorrectionWidth + + parseInt($(v).css('border-left-width')) + + parseInt($(v).css('padding-left')) + + $(v).width() + + parseInt($(v).css('padding-right')) + + parseInt($(v).css('border-right-width')) + ); + + y2 = Math.max(y2, ofs.top + t[n].forceCorrectionTop + t[n].forceCorrectionHeight + + parseInt($(v).css('border-top-width')) + + parseInt($(v).css('padding-top')) + + $(v).height() + + parseInt($(v).css('padding-bottom')) + + parseInt($(v).css('border-bottom-width')) + ); + }); + + switch (t[n].position) { + case 'top': + y = y1 - el.height(); + x = ((x1 + x2) >> 1) - (el.width() >> 1); + break; + + case 'right': + y = ((y1 + y2) >> 1) - (el.height()>> 1); + x = x2; + break; + + case 'left': + y = ((y1 + y2) >> 1) - (el.height()>> 1); + x = x1 - el.width(); + break; + + case 'bottom': + y = y2; + x = ((x1 + x2) >> 1) - (el.width() >> 1); + break; + }; + }; + + el + .css({ + position: 'absolute', + left: x, + top: y + }) + .show(); + + if (t[n].spotlight) { + var p = t[n].padding; + $('body').append(Array(5).join('
')); + + var pos = [ + { + bottom: 'auto', + height: y1 - p + }, + { + top: y2 + p, + height: $(document).height() - y2 - p + }, + { + right: 'auto', + bottom: 'auto', + top: y1 - p, + width: x1 - p, + height: 2 * p + y2 - y1 + }, + { + left: x2 + p, + bottom: 'auto', + top: y1 - p, + height: 2 * p + y2 - y1 + } + ]; + + $('.tourBg') + .css({ + position: 'absolute', + zIndex: 1000, + top: 0, + bottom: 0, + right: 0, + left: 0, + background: '#000', + opacity: 0.3 + }).each(function(k, v){ + $(v).css(pos[k]); + }); + } + + if (!!t[n].scroll) { + var my = ((Math.min(y, y1) + Math.max(y + el.height(), y2)) >> 1) - ($(window).height() >> 1), + mx = ((Math.min(x, x1) + Math.max(x + el.width(), x2)) >> 1) - ($(window).width() >> 1); + + $('html, body').animate({ + scrollTop: Math.max(0, Math.min(y, y1, my)), + scrollLeft: Math.max(0, Math.min(x, x1, mx)) + }); + } + + if (!n) { + $('.tourPrev').remove(); + } + + if (n > t.length - 2) { + $('.tourNext').text(_t('Finish')); + } + + $('.tourStep') + .on('click', '.tourNext:not([disabled])', Tour.next) + .on('click', '.tourPrev:not([disabled])', Tour.prev) + .on('click', '.tourClose:not([disabled])', Tour.close); + + (t[n].onstep || Tour.onstep || function(){})(t[n]); + } + + $(window).on('resize', function() { + if (!!Tour.onresize) { + Tour.onresize(); + } + }); + + return { + run: function(tour, options) { + try { + t = []; + cur = 0; + + o = { + close: true, + content: '', + language: 'en', + padding: 5, + position: 'right', + scroll: true, + spotlight: true, + forceCorrectionLeft: 0, + forceCorrectionTop: 0, + forceCorrectionWidth: 0, + forceCorrectionHeight: 0, + onstep: null, + }; + + for (var k in options) { + o[k] = options[k]; + } + + $(tour).each(function(k, v) { + for (var kk in o) { + v[kk] = v[kk] || o[kk]; + }; + + if (v.element && !!v.element.length) { + t.push(v); + } + }); + + step(cur); + + if (!!Tour.onstart) { + Tour.onstart(); + } + } catch(e) {} + }, + + next: function() { + step(cur + 1); + + if (cur == t.length) { + if (!!Tour.onfinish) { + Tour.onfinish(); + } + } + }, + + prev: function(){ + step(cur - 1); + }, + + current: function(){ + return cur; + }, + + close: function(){ + step(-1); + + if (!!Tour.onclose) { + Tour.onclose(); + } + }, + + onstart: null, + onfinish: null, + onclose: null, + onstep: null, + + onresize: function() { + var n = cur - 1; + step(-1); + cur = n; + + setTimeout(function() { + Tour.next(); + }, 20); + } + }; +})(); diff --git a/ComSemApp/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.min.js b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.min.js new file mode 100755 index 00000000..38939c05 --- /dev/null +++ b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.min.js @@ -0,0 +1,12 @@ +/*! + * DK Notus Tour JavaScript Library v1.2 + * https://github.com/DKNotusIT/DKNotus-Tour/ + * + * Copyright DK Notus and other contributors + * Released under the MIT license + * https://github.com/DKNotusIT/DKNotus-Tour/blob/master/LICENSE + * + * Date: 2018-03-17 + */ + + var Tour=function(){function _t(s){return T[s][t[cur].language]||T[s].en}function step(n){if(cur=n,$(".tourStep, .tourBg").remove(),t[n]){$("body").append(['
','
','
',t[n].close?'':"",'
',t[n].content,"
",'","
","
"].join(""));var el=$(".tourStep").addClass(t[n].position).css({minWidth:250}),x=0,y=0;if(t[n].element&&t[n].element.length){var x1=1e6,y1=1e6,x2=0,y2=0;switch(t[n].element.each(function(k,v){var ofs=$(v).offset();x1=Math.min(x1,ofs.left+t[n].forceCorrectionLeft),y1=Math.min(y1,ofs.top+t[n].forceCorrectionTop),x2=Math.max(x2,ofs.left+t[n].forceCorrectionLeft+t[n].forceCorrectionWidth+parseInt($(v).css("border-left-width"))+parseInt($(v).css("padding-left"))+$(v).width()+parseInt($(v).css("padding-right"))+parseInt($(v).css("border-right-width"))),y2=Math.max(y2,ofs.top+t[n].forceCorrectionTop+t[n].forceCorrectionHeight+parseInt($(v).css("border-top-width"))+parseInt($(v).css("padding-top"))+$(v).height()+parseInt($(v).css("padding-bottom"))+parseInt($(v).css("border-bottom-width")))}),t[n].position){case"top":y=y1-el.height(),x=(x1+x2>>1)-(el.width()>>1);break;case"right":y=(y1+y2>>1)-(el.height()>>1),x=x2;break;case"left":y=(y1+y2>>1)-(el.height()>>1),x=x1-el.width();break;case"bottom":y=y2,x=(x1+x2>>1)-(el.width()>>1)}}if(el.css({position:"absolute",left:x,top:y}).show(),t[n].spotlight){var p=t[n].padding;$("body").append(Array(5).join('
'));var pos=[{bottom:"auto",height:y1-p},{top:y2+p,height:$(document).height()-y2-p},{right:"auto",bottom:"auto",top:y1-p,width:x1-p,height:2*p+y2-y1},{left:x2+p,bottom:"auto",top:y1-p,height:2*p+y2-y1}];$(".tourBg").css({position:"absolute",zIndex:1e3,top:0,bottom:0,right:0,left:0,background:"#000",opacity:.3}).each(function(k,v){$(v).css(pos[k])})}if(t[n].scroll){var my=(Math.min(y,y1)+Math.max(y+el.height(),y2)>>1)-($(window).height()>>1),mx=(Math.min(x,x1)+Math.max(x+el.width(),x2)>>1)-($(window).width()>>1);$("html, body").animate({scrollTop:Math.max(0,Math.min(y,y1,my)),scrollLeft:Math.max(0,Math.min(x,x1,mx))})}n||$(".tourPrev").remove(),n>t.length-2&&$(".tourNext").text(_t("Finish")),$(".tourStep").on("click",".tourNext:not([disabled])",Tour.next).on("click",".tourPrev:not([disabled])",Tour.prev).on("click",".tourClose:not([disabled])",Tour.close),(t[n].onstep||Tour.onstep||function(){})(t[n])}}var o,cur,t=[];return T={step:{pl:"krok",en:"step",be:"крок",ca:"pas",cs:"krok",da:"trin",de:"Schritt",el:"βήμα",es:"paso",et:"samm",fi:"vaihe",fr:"étape",hu:"lépés",it:"passo",lt:"žingsnis",lv:"solis",mk:"чекор",nl:"stap",no:"trinn",pt:"passo",ru:"шаг",sk:"krok",sl:"korak",sq:"hapi",sv:"steg",tr:"adım",uk:"крок"},Next:{pl:"Następny",en:"Next",be:"Далей",ca:"Següent",cs:"Další",da:"Næste",de:"Weiter",el:"Την επόμενη",es:"Siguiente",et:"Järgmine",fi:"Seuraava",fr:"Prochaine",hu:"Következő",it:"Accanto",lt:"Kitas",lv:"Nākamā",mk:"Следна",nl:"Volgende",no:"Neste",pt:"Próximo",ru:"Далее",sk:"Ďalej",sl:"Naprej",sq:"Tjetër",sv:"Nästa",tr:"Gelecek",uk:"Далі"},Previous:{pl:"Poprzedni",en:"Previous",be:"Папярэдні",ca:"Anteriors",cs:"Předchozí",da:"Tidligere",de:"Vorherige",el:"Προηγούμενο",es:"Anterior",et:"Eelmine",fi:"Edellinen",fr:"Précédente",hu:"Előző",it:"Precedente",lt:"Ankstesnis",lv:"Iepriekšējā",mk:"Претходна",nl:"Vorige",no:"Tidligere",pt:"Anterior",ru:"Предыдущий",sk:"Predchádzajúce",sl:"Prejšnji",sq:"E mëparshme",sv:"Föregående",tr:"Önceki",uk:"Попередній"},Finish:{pl:"Zakończ",en:"Finish",be:"Аздабленне",ca:"Acabat",cs:"Dokončit",da:"Finish",de:"Finish",el:"Τελειώνει",es:"Acabado",et:"Lõpeta",fi:"Loppuun",fr:"Finition",hu:"Befejezés",it:"Finitura",lt:"Apdaila",lv:"Apdare",mk:"Заврши",nl:"Afwerking",no:"Ferdig",pt:"Acabamento",ru:"Отделка",sk:"Povrch",sl:"Zaključek",sq:"Finish",sv:"Avsluta",tr:"Bitir",uk:"Оздоблення"}},$(window).on("resize",function(){Tour.onresize&&Tour.onresize()}),{run:function(tour,options){try{t=[],cur=0,o={close:!0,content:"",language:"en",padding:5,position:"right",scroll:!0,spotlight:!0,forceCorrectionLeft:0,forceCorrectionTop:0,forceCorrectionWidth:0,forceCorrectionHeight:0,onstep:null};for(var k in options)o[k]=options[k];$(tour).each(function(k,v){for(var kk in o)v[kk]=v[kk]||o[kk];v.element&&v.element.length&&t.push(v)}),step(cur),Tour.onstart&&Tour.onstart()}catch(e){}},next:function(){step(cur+1),cur==t.length&&Tour.onfinish&&Tour.onfinish()},prev:function(){step(cur-1)},current:function(){return cur},close:function(){step(-1),Tour.onclose&&Tour.onclose()},onstart:null,onfinish:null,onclose:null,onstep:null,onresize:function(){var n=cur-1;step(-1),cur=n,setTimeout(function(){Tour.next()},20)}}}(); \ No newline at end of file diff --git a/ComSemApp/static/ComSemApp/DKNotus-Tour-master/examples.html b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/examples.html new file mode 100755 index 00000000..52867654 --- /dev/null +++ b/ComSemApp/static/ComSemApp/DKNotus-Tour-master/examples.html @@ -0,0 +1,768 @@ + + + + + + DK Notus Tour - Examples + + + + + + +
+ + + + +
+
+

+ This compact solution for guided tours has + 27 languages support. + It requires only two very common dependencies: + jQuery and Bootstrap. + Also has useful features like auto scroll + and "spotlight". + We hope you enjoy it. +

+ +
+ DK Notus Tour +
+ +

+ We tried to keep all data regarding usage as short as possible. +

+ +

1. Features

+ +

+ Features that we considerble important: +

+ +
+
small requirements
+
only jQuery and Bootstrap;
+ +
simple usage
+
one function for common usage - yes, it's that simple;
+ +
events
+
for advanced programmers usage;
+ +
scroll
+
and some more useful features;
+ +
multi elem. selection
+
you can point more then one element for one tour step;
+ +
translations
+
languages support.
+
+ +

2. Simple use case

+ +

Lets start with two step tour for elements below:

+ + + + + +

+ First of all we need to include two common libraries + jQuery and Bootstrap. + You ca use some CDN for that. +

+ +
+
  <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
+  <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
+
+ +

+ Then it's time tour library dknotus-tour.js + or dknotus-tour.min.js. +

+ +
+
  <script src="dknotus-tour.js"></script>
+
+ +

+ Finally we can define our own tour and run it with + Tour.run(). Yes, it's that simple. +

+ + + +
+
+  $(function(){
+    $('#simpleBtn').click(function(){
+      Tour.run([
+        {
+          element: $('#btn1'),
+          content: 'first btn'
+        },
+        {
+          element: $('#btn2'),
+          content: 'and the second one<br>description might be <strong>HTML</strong>'
+        },
+      ]);
+    });
+  });
+            
+
+ +

3. Different tour positions

+ + + + + + + +
+
+  $(function(){
+    $('#positionsBtn').click(function(){
+      Tour.run([
+        {
+          element: $('#posBtn'),
+          content: 'by default tour is on the right'
+        },
+        {
+          element: $('#posBtn'),
+          content: 'but it can be on top',
+          position: 'top'
+        },
+        {
+          element: $('#posBtn'),
+          content: 'bottom',
+          position: 'bottom'
+        },
+        {
+          element: $('#posBtn'),
+          content: 'and finally on the left',
+          position: 'left'
+        }
+      ]);
+    });
+  });
+
+ +

4. Global and local parameters

+ +

+ Tour may be run with two parameters: tour description (mandatory) + and global options (optional) Tour.run(tourDescription, + options). If for some tour hint some parameter is not set, + then if it's possible it's taken from options. +

+ +

+ Possible parameters for hints descriptions and for global options +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDefault valueDescription
elementnone + jQuery element (might be more then one), + if it's not set then hint is skipped. +
contentempty stringIt's for contents of particular hints.
closetrueDefines if close button should be shown.
languageen + Defines interface language. Available languages: +
+
en
+
English (default)
+ +
pl
+
Polish
+ +
be
+
Belarusian
+ +
ca
+
Catalan
+ +
cs
+
Czech
+ +
da
+
Danish
+ +
de
+
German
+ +
el
+
Greek
+ +
es
+
Spanish
+ +
et
+
Estonian
+ +
fi
+
Finnish
+ +
fr
+
French
+ +
hu
+
Hungarian
+ +
it
+
Italian
+ +
lt
+
Lithuanian
+ +
lv
+
Latvian
+ +
mk
+
Macedonian
+ +
nl
+
Dutch
+ +
no
+
Norwegian
+ +
pt
+
Portuguese
+ +
ru
+
Russian
+ +
sk
+
Slovak
+ +
sl
+
Slovenian
+ +
sq
+
Albanian
+ +
sv
+
Swedish
+ +
tr
+
Turkish
+ +
uk
+
Ukrainian
+
+
padding5 + Extra space around tour exposed elements. + (Has only sense when spotlight option is true). +
positionright + Determines where hint should be shown relativly to element + it describes.
+ Possible values: right, left, top and bottom. +
scrolltrue + If true then scrolls window so selected element + and hint would be as close as possible to the view center. +
spotlighttrue + If true then covers everything except selected element + and hint with shadow. +
forceCorrectionLeft0 + Useful if for some reason left offset needs to be modified. +
forceCorrectionTop0 + Useful if for some reason top offset needs to be modified. +
forceCorrectionWidth0 + Useful if for some reason width needs to be modified. +
forceCorrectionHeight0 + Useful if for some reason height needs to be modified. +
+ +

+ All above options can be used for both: single hint description + and for global options. With global options previous example + can be writen like: +

+ +
+
+  $(function(){
+    $('#positionsShorterBtn').click(function(){
+      var globalOptions = {
+        element: $('#posBtn')
+      };
+
+      var tourDescription = [
+        {
+          content: 'by default tour is on the right'
+        },
+        {
+          content: 'but it can be on top',
+          position: 'top'
+        },
+        {
+          content: 'bottom',
+          position: 'bottom'
+        },
+        {
+          content: 'and finally on the left',
+          position: 'left'
+        }
+      ];
+
+      Tour.run(tourDescription, globalOptions);
+    });
+  });
+
+ + + + + +

5. Events example

+ +

+ There are four events that can be used by developers: +

+ +
+
onstart()
+
Triggered when new tour starts ( Tour.run() ).
+ +
onfinish()
+
Triggered when Finish button is clicked.
+ +
onclose()
+
+ Triggered when Close button is pressed + ( Tour.close() ). +
+ +
onstep( currentStep )
+
+ Triggered on every step shown + ( Tour.next() or Tour.prev() ). +
+ +
onresize
+
By default this one is set.
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+ + + + + +
+
+  $(function(){
+    $('#eventsBtn').click(function(){
+      Tour.onstart = function(){
+        console.log('We started!');
+      };
+
+      Tour.onfinish = function(){
+        console.log('The End');
+      };
+
+      Tour.onclose = function(){
+        console.log('Tour interupted');
+      };
+
+      Tour.onstep = function(currentStep){
+        console.log('"That\'s one small step for a man ..."');
+        console.log(currentStep);
+      };
+
+      Tour.run([
+        {
+          element: $('#eventBtn1').add('#eventBtn3'),
+          content: 'You prefer photos?',
+          position: 'top'
+        },
+        {
+          element: $('#eventBtn3').add('#eventBtn4'),
+          content: 'or videos?',
+          onstep: function(currentStep) {
+            console.log('Events defined in step, overwrites global definition');
+          }
+        }
+      ]);
+    });
+  });
+
+ +

6. Tour interface

+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Tour.run( tourDescription, globlOptions )Function for running Tour;
Tour.next()Goes to next tour step;
Tour.prev()Goes to previous tour step;
Tour.close()Interrupts tour and closes it;
Tour.current()Returns current step description.
+ +

Events

+ +

+ By default all except onresize are set to null. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
EventDescription
Tour.onstart() + Triggered when new tour starts ( Tour.run() ); +
Tour.onfinish()Triggered when Finish button is clicked;
Tour.onclose() + Triggered when Close button is pressed + ( Tour.close() ); +
Tour.onstep( currentStep ) + Triggered on every step shown + ( Tour.next() or Tour.prev() ); +
Tour.onresize()By default this one is set.
+ +

7. Contact

+ + Jan Doleczek + +
+ + No animals were harmed during development. + + + + DK Notus 2016 + + +
+ + +
+
+ + diff --git a/ComSemApp/student/urls.py b/ComSemApp/student/urls.py index 1bfe9260..ad457135 100644 --- a/ComSemApp/student/urls.py +++ b/ComSemApp/student/urls.py @@ -4,6 +4,9 @@ app_name = 'student' urlpatterns = [ url(r'^$', views.CourseListView.as_view(), name='courses'), + + # url(r'^course/googleTranscribe/$', views.googleTranscribe, name="googleTranscribe"), + url(r'^course/(?P[0-9]+)/$', views.CourseDetailView.as_view(), name='course'), url(r'^course/(?P[0-9]+)/worksheet/(?P[0-9]+)/submission/list/$', views.SubmissionListView.as_view(), name='submission_list'), url(r'^course/(?P[0-9]+)/worksheet/(?P[0-9]+)/submission/create/$', views.SubmissionCreateView.as_view(), name='create_submission'), @@ -15,4 +18,4 @@ url(r'^course/(?P[0-9]+)/reviewsheet/$', views.ReviewsheetGetView.as_view(), name='create_reviewsheet'), url(r'^course/(?P[0-9]+)/reviewsheet/$', views.ReviewsheetView.as_view(), name='reviewsheet'), url(r'^course/(?P[0-9]+)/reviewsheet/save$', views.ReviewAttemptCreateView.as_view(), name='save_reviewsheet'), -] \ No newline at end of file +] diff --git a/ComSemApp/student/views.py b/ComSemApp/student/views.py index 82d90b42..612f77b0 100644 --- a/ComSemApp/student/views.py +++ b/ComSemApp/student/views.py @@ -18,7 +18,6 @@ from ComSemApp.models import * from ComSemApp.libs.mixins import RoleViewMixin, CourseViewMixin, WorksheetViewMixin, SubmissionViewMixin - class StudentViewMixin(RoleViewMixin): role_class = Student @@ -71,15 +70,48 @@ def get_object(self): def get_context_data(self, **kwargs): context = super(CourseDetailView, self).get_context_data(**kwargs) + worksheets = self.course.worksheets.filter(status=teacher_constants.WORKSHEET_STATUS_RELEASED) + submissions = StudentSubmission.objects.filter(student=self.student) + expressionList = [] + context['complete'] = 0 + context['incomplete'] = 0 + context['ungraded']= 0 + context['expressionCount']= 0 + worksheets = self.course.worksheets.filter(status=teacher_constants.WORKSHEET_STATUS_RELEASED).order_by('-date') - # TODO should this logic be in the worksheet model ? + # TODO should this logic be in the worksheet model? for worksheet in worksheets: + expression_filters = Q(worksheet=worksheet) + if not worksheet.display_all_expressions: + expression_filters &= (Q(student=self.student) | Q(student=None) | Q(all_do=True) | Q(worksheet=worksheet)) + expressions = Expression.objects.filter(expression_filters) + complete_submission = worksheet.complete_submission(self.student) # vhl checks for complete submissions. complete_submission_status = 'complete' if complete_submission else "none" - + last_submission = worksheet.last_submission(self.student) last_submission_status = last_submission.status if last_submission else "none" + + # Loop through and count status of worksheets/expressions + if last_submission_status == "incomplete" or last_submission_status == "none": + context['incomplete'] += 1 + for expression in expressions: + if expression.worksheet == worksheet: + expressionList.append(expression.expression) + if last_submission_status == "complete": + context['complete'] += 1 + for expression in expressions: + print('COMPLETE') + print(expression.expression) + if expression.worksheet == worksheet: + context['expressionCount'] += 1 + if last_submission_status == "ungraded": + context['ungraded'] += 1 + for expression in expressions: + if expression.worksheet == worksheet: + expressionList.append(expression.expression) + last_submission_id = last_submission.id if last_submission else 0 status_colors = { "complete": "success", @@ -117,9 +149,10 @@ def get_context_data(self, **kwargs): worksheet.status_color = status_colors[last_submission_status] worksheet.button_text = button_texts[last_submission_status] worksheet.link_url = link_urls[last_submission_status] - - + + context['expressions'] = expressionList context['worksheets'] = worksheets + return context diff --git a/ComSemApp/teacher/views.py b/ComSemApp/teacher/views.py index 33fd91fb..5614d4a9 100644 --- a/ComSemApp/teacher/views.py +++ b/ComSemApp/teacher/views.py @@ -23,6 +23,7 @@ import json, math, datetime, os, csv from ComSemApp.models import * +from django.template.defaulttags import register class TeacherViewMixin(RoleViewMixin): @@ -76,7 +77,53 @@ def get_context_data(self, **kwargs): class CourseDetailView(TeacherCourseViewMixin, DetailView): context_object_name = 'course' template_name = "ComSemApp/teacher/course.html" + + @register.filter('get_item') + def get_item(dictionary, key): + return dictionary.get(key) + def get_context_data(self, **kwargs): + data = super().get_context_data(**kwargs) + + worksheets = Worksheet.objects.filter(course=self.course) + worksheetsdict = {} + ungradedcountdict = {} + attemptsdict = {} + for student in self.course.students.all(): + worksheetcount = 0 + ungradedcount = 0 + attemptcount = 0 + submissions = StudentSubmission.objects.filter(student=student) + for submission in submissions : + if submission.worksheet.course == self.course: + if submission.status == 'ungraded': + ungradedcount = ungradedcount + 1 + + for worksheet in worksheets: + if worksheet.last_submission(student): + attemptcount = attemptcount + worksheet.last_submission(student).get_number() + worksheetcount = worksheetcount + 1 + + worksheetsdict[student.user.username] = worksheetcount + ungradedcountdict[student.user.username] = ungradedcount + attemptsdict[student.user.username] = attemptcount + + submissions = StudentSubmission.objects.filter(worksheet__course=self.course) + ungraded = submissions.filter(status="ungraded").count() + complete = submissions.filter(status="complete").count() + incomplete = submissions.filter(status="incomplete").count() + submissions = StudentSubmission.objects.all() + + + data['classungraded'] = ungraded + data['classincomplete'] = incomplete + data['classcomplete'] = complete + data['ungradedSubmissions'] = len(self.course.worksheets.all()) + data['worksheets'] = worksheetsdict + data['ungraded'] = ungradedcountdict + data['attempts'] = attemptsdict + + return data def get_object(self): return self.course diff --git a/ComSemApp/templates/ComSemApp/admin/student_list.html b/ComSemApp/templates/ComSemApp/admin/student_list.html index 961f718d..a4884efb 100644 --- a/ComSemApp/templates/ComSemApp/admin/student_list.html +++ b/ComSemApp/templates/ComSemApp/admin/student_list.html @@ -8,13 +8,41 @@

All Students

- + + +
{% csrf_token %} + +
+ +
+ +
+
+

Uploader only allows CSV Files. +

+

+ Please order students in the following way: firstname, lastname, email, username. + Below is an example of how the first line would look, a comma indicates a new column. Names must contain letters only. +

+

+ John,Doe,johndoe@gmail.com,johnsusername +

+
+ +
+ {% if messages %} + {% for message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %}

diff --git a/ComSemApp/templates/ComSemApp/base.html b/ComSemApp/templates/ComSemApp/base.html index e4e9ddb8..50e00914 100644 --- a/ComSemApp/templates/ComSemApp/base.html +++ b/ComSemApp/templates/ComSemApp/base.html @@ -34,6 +34,7 @@ + diff --git a/ComSemApp/templates/ComSemApp/course_table.html b/ComSemApp/templates/ComSemApp/course_table.html index 219e3a46..9fb87900 100644 --- a/ComSemApp/templates/ComSemApp/course_table.html +++ b/ComSemApp/templates/ComSemApp/course_table.html @@ -6,6 +6,9 @@

My Courses

+
+ +
diff --git a/ComSemApp/templates/ComSemApp/messages.html b/ComSemApp/templates/ComSemApp/messages.html index a6c53c3f..8e672764 100644 --- a/ComSemApp/templates/ComSemApp/messages.html +++ b/ComSemApp/templates/ComSemApp/messages.html @@ -19,7 +19,6 @@ var cs_ajax_error = function(jqXHR, textStatus, errorThrown){ cs_notification('error', errorThrown) } - function cs_notification(tag, message){ $.Notification.notify(tag, 'right bottom', message) } @@ -28,4 +27,4 @@ - + \ No newline at end of file diff --git a/ComSemApp/templates/ComSemApp/student/attempt_form.html b/ComSemApp/templates/ComSemApp/student/attempt_form.html index ad2365d3..76384704 100644 --- a/ComSemApp/templates/ComSemApp/student/attempt_form.html +++ b/ComSemApp/templates/ComSemApp/student/attempt_form.html @@ -1,8 +1,8 @@ {% load static %} - - + + @@ -11,6 +11,7 @@
+

{{ expression.expression }}

@@ -69,6 +70,11 @@ +
+ +

+
+
@@ -95,6 +101,61 @@ + + \ No newline at end of file diff --git a/ComSemApp/templates/ComSemApp/student/course.html b/ComSemApp/templates/ComSemApp/student/course.html index 53263a47..21045feb 100644 --- a/ComSemApp/templates/ComSemApp/student/course.html +++ b/ComSemApp/templates/ComSemApp/student/course.html @@ -3,6 +3,94 @@ {% block content %}
+
+
+ +
+
+ +

Stats

+
+
+
+
+
+

{{ expressionCount }}

+
+
+

Expressions Completed

+
+
+
+
+
+
+

{{ complete }}

+
+
+

Worksheets Completed

+
+
+
+
+
+
+
+
+

{{ incomplete }}

+
+
+

Worksheets Incomplete

+
+
+
+
+
+
+

{{ ungraded }}

+
+
+

Worksheets to Grade

+
+
+
+
+
+
+
+ +
+
+

Worksheet Status

+ +
+
+
+ +
+
+
+

Assigned Expressions

+ +
+ + + + + + {% for expression in expressions %} + + + + {% endfor %} + +
{{ expression }}
+
+
+
+
+
+
{% include 'ComSemApp/course_details.html' %} @@ -48,11 +136,51 @@

Worksheets

{% include 'ComSemApp/tablesorter_footer.html'%} - {% else %} + {% else %}

No worksheets available

{% endif %}
+ +
+ + +
+ {% endblock %} diff --git a/ComSemApp/templates/ComSemApp/student/create_submission.html b/ComSemApp/templates/ComSemApp/student/create_submission.html index 2c9412ac..8b874abe 100644 --- a/ComSemApp/templates/ComSemApp/student/create_submission.html +++ b/ComSemApp/templates/ComSemApp/student/create_submission.html @@ -13,10 +13,10 @@

Create Submission

- +
{% csrf_token %} - +
@@ -94,7 +94,6 @@

- + {% endblock %} diff --git a/ComSemApp/templates/ComSemApp/student/expression_list.html b/ComSemApp/templates/ComSemApp/student/expression_list.html index d4e7fec7..000d58d9 100644 --- a/ComSemApp/templates/ComSemApp/student/expression_list.html +++ b/ComSemApp/templates/ComSemApp/student/expression_list.html @@ -53,7 +53,8 @@ audioReformulationBlob = null; // clears reformulation }); }) - + + {% else %}

This worksheet has no expressions.
-{% endif %} +{% endif %} \ No newline at end of file diff --git a/ComSemApp/templates/ComSemApp/teacher/course.html b/ComSemApp/templates/ComSemApp/teacher/course.html index e1da0650..3f5e2b9b 100644 --- a/ComSemApp/templates/ComSemApp/teacher/course.html +++ b/ComSemApp/templates/ComSemApp/teacher/course.html @@ -5,6 +5,7 @@
+

Course Information

@@ -16,7 +17,23 @@

Course Information

- {% include 'ComSemApp/course_details.html' %} +
+ {% include 'ComSemApp/course_details.html' %} +
+ +
Download All Sentences @@ -41,13 +58,60 @@

Students

- {% include 'ComSemApp/teacher/course_students.html' %} + {% include 'ComSemApp/teacher/course_students_detail.html' %}
+
+
+
+
+
+
+
+
+
+ +
@@ -63,7 +127,7 @@

Students

Worksheets

@@ -148,4 +212,16 @@

Worksheets

+ + + {% endblock %} diff --git a/ComSemApp/templates/ComSemApp/teacher/course_students.html b/ComSemApp/templates/ComSemApp/teacher/course_students.html index fb91437d..78be64c9 100644 --- a/ComSemApp/templates/ComSemApp/teacher/course_students.html +++ b/ComSemApp/templates/ComSemApp/teacher/course_students.html @@ -1,3 +1,4 @@ + {% if course.students.all %} diff --git a/ComSemApp/templates/ComSemApp/teacher/course_students_detail.html b/ComSemApp/templates/ComSemApp/teacher/course_students_detail.html new file mode 100644 index 00000000..12d1fb8f --- /dev/null +++ b/ComSemApp/templates/ComSemApp/teacher/course_students_detail.html @@ -0,0 +1,32 @@ +{% load static %} +{% if course.students.all %} + + + Name + Worksheets Assigned + Ungraded Submissions + Number of Attempts + + + + + + {% for student in course.students.all %} + + {{student}} + + {{ worksheets|get_item:student.user.username }} + + + {{ ungraded|get_item:student.user.username }} + + + {{ attempts|get_item:student.user.username }} + + Email + + {% endfor %} + +{% else %} +

No Enrolled Students

+{% endif %} \ No newline at end of file diff --git a/ComSemApp/templates/ComSemApp/teacher/edit_worksheet.html b/ComSemApp/templates/ComSemApp/teacher/edit_worksheet.html index 21df3f12..1d7cb6da 100644 --- a/ComSemApp/templates/ComSemApp/teacher/edit_worksheet.html +++ b/ComSemApp/templates/ComSemApp/teacher/edit_worksheet.html @@ -4,8 +4,11 @@ {% block content %} + +
+ {% csrf_token %} @@ -32,8 +35,8 @@

-

Worksheet Info

+

Worksheet Info

@@ -44,7 +47,7 @@

Worksheet Info

-
+
@@ -73,7 +76,6 @@

Worksheet Info

-
@@ -81,9 +83,8 @@

Worksheet Info

- +
-
+ + {% endblock %} diff --git a/ComSemApp/templates/ComSemApp/teacher/expression_form.html b/ComSemApp/templates/ComSemApp/teacher/expression_form.html index 65f5ef3a..97fb52e0 100644 --- a/ComSemApp/templates/ComSemApp/teacher/expression_form.html +++ b/ComSemApp/templates/ComSemApp/teacher/expression_form.html @@ -1,11 +1,12 @@ {% load static %} - - + + + -
- + +
+ +

+
+
+
{% include 'ComSemApp/audio_recording.html' %}
@@ -117,6 +125,18 @@

- inspectFormData(worksheetFormData) - - $.ajax({ - type: "POST", - url: $("#create_or_update_url").val(), - data: worksheetFormData, - processData: false, - contentType: false, - success: function(response){ - cs_notification('success', "Expression Saved") - // update expressions table - drawExpressionsTable(); + \ No newline at end of file diff --git a/ComSemApp/templates/ComSemApp/teacher/worksheet_list.html b/ComSemApp/templates/ComSemApp/teacher/worksheet_list.html index 2d8cc812..d9badf6c 100644 --- a/ComSemApp/templates/ComSemApp/teacher/worksheet_list.html +++ b/ComSemApp/templates/ComSemApp/teacher/worksheet_list.html @@ -45,4 +45,4 @@ {% else %}

No worksheets have been created yet. Click here to create one.

-{% endif %} +{% endif %} \ No newline at end of file diff --git a/ComSemApp/templates/registration/login.html b/ComSemApp/templates/registration/login.html index d7c17bd3..c4c9d4cf 100644 --- a/ComSemApp/templates/registration/login.html +++ b/ComSemApp/templates/registration/login.html @@ -60,14 +60,16 @@ Forgot your password?
-
-
+ + diff --git a/CommunicationSeminar-7d71fc1430af.json b/CommunicationSeminar-7d71fc1430af.json new file mode 100644 index 00000000..92aa5f78 --- /dev/null +++ b/CommunicationSeminar-7d71fc1430af.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "communicationsem-1551739563072", + "private_key_id": "7d71fc1430afbbc39e7c036244c1030b6d67442c", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDY7VjU3PReWgam\nJPvYcotxezUpw3ot1wSDNCzYb/jpI6U8COeicsBMxd3Tw4xtNwSIqRFTJjR5VQBV\nmk1UaKQcDFFicBZgNq4GMGSxpy62dxpsRP8jaclGd5Vw5LicA2duvslYMML41nfx\nL9i10z62lzOrY4/QjMDdV+5FCq1ijYZWwx4UzVPEQRugBZ/XarxCQnn6+IC9TyCT\nnLCQ/WJ+r9jUDYX4XeAegWs0cp9IqN9bTFwWGkRpKAHxuKJKjNjvuPwKfYKe4g2k\ntHN2xP0p2o5vSpE08QxCY83XO3kZBgTLBAPXdC3D1O62m1Ex8XLGB3QmL0+dl/CT\n+F44tL5vAgMBAAECggEAHm8uR1m4mdmHlUfFuFhZt/zROKAe7s975+x/XjOszbNy\nkI8EmzCo9McjQtKXS7tW/NVmLi7uAxfUiYNcgLstoGxvU/WQg28oezXO6sh0hU+w\neqreINnL+KxOYHMLyNexa0LZJ3EFPw7X776xaNElEKOmBtBbx6aiaGuDF6yn0Wuc\n4OFPlBFWFQyW3nwyQ2VxlAOhExa9D5qszahzhRfsZQIh78JnStrEXct1GdAzIgl8\n+0UVI98VgZ1Y/jXQsC9qjpSZjFvbxmDSitdKEfzu519UciW5wTUvzcrV2KDX4hP9\nry91NHr+EnLK9pbUsDem5KO5bHWsAB4EMOoBFaPGAQKBgQDvQtWUkAG9QnW7Mr0+\nNj76U5jpuYMyvKaRfenYlM6B/5Lsjmj6aWfKRUTy0aSUUjKYlfWsZmQGkyRYbWct\n//NYqE6wsTi3neVYB+PWp7cckMvAShGvlhtoHiQ3TZcDMN2fg+9lHQopjGxF3Ljb\nPmYCw81i7PnsYCZyi94OvhqQbQKBgQDoGoMOROsVJCuQhuLwyX6gQh5I8OgVsjAV\nYuqk0uF4ozzNx03HLhZUbBl+edJvIepspv0iXqqL7FtsKjd/tOq5Wwokasnph+ma\nQyYn1fygoGITvzjY0JvZhAbDSSjAqln/nus3kK6yd/qM+GyKi0G8b9CxJOPtUyQo\nFapwwEIYywKBgDo57JpL9XBmlRoqfe1+7BKld4ghsnENggfUOa2QgTUXylyxR5Dx\nR+Xst5vUMxY5bsC9dd0vydXjxyuR7FNAf6sqwoOzjVb6IQ8sVGEvzZsxDbTNEcLG\naAMNmsiupDqNkNG6HO9hgtCbsNnLnl0UsWSo2/ngK+4/c/vaV/8Eeph9AoGBAJIC\n+6ciW/D0zCMjd+iaGXqfnYWtZ5MegXkyvQHrV8QYjMu3MYq3x3xcdL1HzcXzxBGO\nC3hvrUJQ8kJdXISOP4tTZlH6jALJaX+N9pbg2wgBXTGm/hAHS8POdqKrh2OMxwkz\n5C0Ua5ICQDAmp8GQUU5F2TdXSbumrfw5hPthNzN5AoGAYFby81jrjNmL1+2qFzch\nAOstKnE8Tfsf70EX6mpITqd+AVe4lCIzPnWsRlY/xSO5mFBcGqfpZlKqyIzj49kK\nkdTVKAR7xFesKT7Xgv8KYAYSbZXLBp/z8FUwCvrxXfcLd321LIf0tSkoySrcw3BG\nwWweesIuRbUDKXlv/hZzpaA=\n-----END PRIVATE KEY-----\n", + "client_email": "starting-account-9jnnspij26oc@communicationsem-1551739563072.iam.gserviceaccount.com", + "client_id": "109876849879407886090", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/starting-account-9jnnspij26oc%40communicationsem-1551739563072.iam.gserviceaccount.com" +} diff --git a/GoogleSpeech_Start.sh b/GoogleSpeech_Start.sh new file mode 100755 index 00000000..fd6bc353 --- /dev/null +++ b/GoogleSpeech_Start.sh @@ -0,0 +1 @@ +export GOOGLE_APPLICATION_CREDENTIALS="CommunicationSeminar-7d71fc1430af.json" diff --git a/googletest.py b/googletest.py new file mode 100644 index 00000000..e3526346 --- /dev/null +++ b/googletest.py @@ -0,0 +1,33 @@ +import io +import os + +# Imports the Google Cloud client library +from google.cloud import speech +from google.cloud.speech import enums +from google.cloud.speech import types + +# Instantiates a client +client = speech.SpeechClient() + +# The name of the audio file to transcribe +file_name = "efs/reformulations/41c87965-0174-4231-8253-db494f9a8a61.ogg" + +# Loads the audio into memory +with io.open(file_name, 'rb') as audio_file: + content = audio_file.read() + +audio = types.RecognitionAudio(content=content) + +# for i in range(8000, 48001, 2000): +for i in [8000, 12000, 16000, 24000, 48000]: + print(i) + config = types.RecognitionConfig( + encoding=enums.RecognitionConfig.AudioEncoding.OGG_OPUS, + sample_rate_hertz=i, + language_code='en-US') + + # Detects speech in the audio file + response = client.recognize(config, audio) + print("Recognizing") + for result in response.results: + print('Transcript: {}'.format(result.alternatives[0].transcript)) diff --git a/static/ComSemApp/DKNotus-Tour-master/DKNotusTour.png b/static/ComSemApp/DKNotus-Tour-master/DKNotusTour.png new file mode 100644 index 00000000..126344fe Binary files /dev/null and b/static/ComSemApp/DKNotus-Tour-master/DKNotusTour.png differ diff --git a/static/ComSemApp/DKNotus-Tour-master/LICENSE b/static/ComSemApp/DKNotus-Tour-master/LICENSE new file mode 100644 index 00000000..5b132a5e --- /dev/null +++ b/static/ComSemApp/DKNotus-Tour-master/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 DK Notus IT Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/static/ComSemApp/DKNotus-Tour-master/README.md b/static/ComSemApp/DKNotus-Tour-master/README.md new file mode 100644 index 00000000..630e86e7 --- /dev/null +++ b/static/ComSemApp/DKNotus-Tour-master/README.md @@ -0,0 +1,235 @@ +# DK Notus Tour + +#### This compact solution for guided tours has 27 languages support. It requires only two very common dependencies: **jQuery** and **Bootstrap**. Also has useful features like auto scroll and "spotlight". We hope you enjoy it. + +![DK Notus Tour](DKNotusTour.png) + +We tried to keep all data regarding usage as short as possible. +## 1. Features + +Features that we considerble important: + + - **small requirements** - only jQuery and Bootstrap; + - **simple usage** - one function for common usage - yes, it's that simple; + - **events** - for advanced programmers usage; + - **scroll** - and some more useful features; + - **multi elements selection** - you can point more then one element for one tour step; + - **translations** - 27 languages support. + +## 2. Simple use case + +Lets start with two step tour for elements below: + +First of all we need to include two common libraries jQuery and Bootstrap. You ca use some CDN for that. + + + + +Then it's time tour library `dknotus-tour.js` or `dknotus-tour.min.js`. + + + +Finally we can define our own tour and run it with Tour.run(). Yes, it's that simple. + +```javascript + $(function(){ + $('#simpleBtn').click(function(){ + Tour.run([ + { + element: $('#btn1'), + content: 'first btn' + }, + { + element: $('#btn2'), + content: 'and the second one
description might be HTML' + }, + ]); + }); + }); +``` + +## 3. Different tour positions +```javascript + $(function(){ + $('#positionsBtn').click(function(){ + Tour.run([ + { + element: $('#posBtn'), + content: 'by default tour is on the right' + }, + { + element: $('#posBtn'), + content: 'but it can be on top', + position: 'top' + }, + { + element: $('#posBtn'), + content: 'bottom', + position: 'bottom' + }, + { + element: $('#posBtn'), + content: 'and finally on the left', + position: 'left' + } + ]); + }); + }); +``` + +## 4. Global and local parameters + +Tour may be run with two parameters: tour description (mandatory) and global options (optional) Tour.run(tourDescription, options). If for some tour hint some parameter is not set, then if it's possible it's taken from options. + +Possible parameters for hints descriptions and for global options: + +Parameter | Default value | Description +--------- | ------------- | ----------- +element | *none* | jQuery element (might be more then one), if it's not set then hint is skipped. +content | *empty string* | It's for contents of particular hints. +close | true | Defines if close button should be shown. +language | en | Defines interface language. Available languages: +|| en | English (default) +|| pl | Polish +|| be | Belarusian +|| ca | Catalan +|| cs | Czech +|| da | Danish +|| de | German +|| el | Greek +|| es | Spanish +|| et | Estonian +|| fi | Finnish +|| fr | French +|| hu | Hungarian +|| it | Italian +|| lt | Lithuanian +|| lv | Latvian +|| mk | Macedonian +|| nl | Dutch +|| no | Norwegian +|| pt | Portuguese +|| ru | Russian +|| sk | Slovak +|| sl | Slovenian +|| sq | Albanian +|| sv | Swedish +|| tr | Turkish +|| uk | Ukrainian +padding | 5 | Extra space around tour exposed elements. (Has only sense when spotlight option is true). +position | right | Determines where hint should be shown relatively to element it describes. +||| Possible values: right, left, top and bottom. +scroll | true | If true then scrolls window so selected element and hint would be as close as possible to the view center. +spotlight | true | If true then covers everything except selected element and hint with shadow. +forceCorrectionLeft | 0 | Useful if for some reason left offset needs to be modified. +forceCorrectionTop | 0 | Useful if for some reason top offset needs to be modified. +forceCorrectionWidth | 0 | Useful if for some reason width needs to be modified. +forceCorrectionHeight | 0 | Useful if for some reason height needs to be modified. + +All above options can be used for both: single hint description and for global options. With global options previous example can be written like: + +```javascript + $(function(){ + $('#positionsShorterBtn').click(function(){ + var globalOptions = { + element: $('#posBtn') + }; + + var tourDescription = [ + { + content: 'by default tour is on the right' + }, + { + content: 'but it can be on top', + position: 'top' + }, + { + content: 'bottom', + position: 'bottom' + }, + { + content: 'and finally on the left', + position: 'left' + } + ]; + + Tour.run(tourDescription, globalOptions); + }); + }); +``` + +## 5. Events example + +There are four events that can be used by developers: + + - **onstart()** - Triggered when new tour starts ( `Tour.run()` ); + - **onfinish()** - Triggered when Finish button is clicked; + - **onclose()** - Triggered when Close button is pressed ( `Tour.close()` ); + - **onstep( currentStep )** - Triggered on every step shown ( `Tour.next()` or `Tour.prev()` ); + - **onresize()** - By default this one is set. + +```javascript + $(function(){ + $('#eventsBtn').click(function(){ + Tour.onstart = function(){ + console.log('We started!'); + }; + + Tour.onfinish = function(){ + console.log('The End'); + }; + + Tour.onclose = function(){ + console.log('Tour interupted'); + }; + + Tour.onstep = function(currentStep){ + console.log('"That\'s one small step for a man ..."'); + console.log(currentStep); + }; + + Tour.run([ + { + element: $('#eventBtn1').add('#eventBtn3'), + content: 'You prefer photos?', + position: 'top' + }, + { + element: $('#eventBtn3').add('#eventBtn4'), + content: 'or videos?', + onstep: function(currentStep) { + console.log('Events defined in step, overwrites global definition'); + } + } + ]); + }); + }); +``` + +## 6. Tour interface + +#### Methods + +Method | Description +------ | ----------- +**Tour.run( tourDescription, globlOptions )** | Function for running Tour. +**Tour.next()** | Goes to next tour step. +**Tour.prev()** | Goes to previous tour step. +**Tour.close()** | Interrupts tour and closes it. +**Tour.current()** | Returns current step description. + +#### Events + +By default all except `onresize` are set to null. + +Event | Description +----- | ----------- +**Tour.onstart()** | Triggered when new tour starts ( Tour.run() ). +**Tour.onfinish()** | Triggered when Finish button is clicked. +**Tour.onclose()** | Triggered when Close button is pressed ( Tour.close() ). +**Tour.onstep( currentEvent )** | Triggered on every step shown ( Tour.next() or Tour.prev() ). +**Tour.onresize()** | By default this one is set. + +## 7. Contact + +Jan Doleczek diff --git a/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.js b/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.js new file mode 100644 index 00000000..d1d25fd5 --- /dev/null +++ b/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.js @@ -0,0 +1,391 @@ +/*! + * DK Notus Tour JavaScript Library v1.2 + * https://github.com/DKNotusIT/DKNotus-Tour/ + * + * Copyright DK Notus and other contributors + * Released under the MIT license + * https://github.com/DKNotusIT/DKNotus-Tour/blob/master/LICENSE + * + * Date: 2018-03-17 + */ + +var Tour = (function() { + var t = [], + o, cur + T = { + step: { + pl: "krok", + en: "step", + be: "крок", + ca: "pas", + cs: "krok", + da: "trin", + de: "Schritt", + el: "βήμα", + es: "paso", + et: "samm", + fi: "vaihe", + fr: "étape", + hu: "lépés", + it: "passo", + lt: "žingsnis", + lv: "solis", + mk: "чекор", + nl: "stap", + no: "trinn", + pt: "passo", + ru: "шаг", + sk: "krok", + sl: "korak", + sq: "hapi", + sv: "steg", + tr: "adım", + uk: "крок" + }, + Next: { + pl: "Następny", + en: "Next", + be: "Далей", + ca: "Següent", + cs: "Další", + da: "Næste", + de: "Weiter", + el: "Την επόμενη", + es: "Siguiente", + et: "Järgmine", + fi: "Seuraava", + fr: "Prochaine", + hu: "Következő", + it: "Accanto", + lt: "Kitas", + lv: "Nākamā", + mk: "Следна", + nl: "Volgende", + no: "Neste", + pt: "Próximo", + ru: "Далее", + sk: "Ďalej", + sl: "Naprej", + sq: "Tjetër", + sv: "Nästa", + tr: "Gelecek", + uk: "Далі" + }, + Previous: { + pl: "Poprzedni", + en: "Previous", + be: "Папярэдні", + ca: "Anteriors", + cs: "Předchozí", + da: "Tidligere", + de: "Vorherige", + el: "Προηγούμενο", + es: "Anterior", + et: "Eelmine", + fi: "Edellinen", + fr: "Précédente", + hu: "Előző", + it: "Precedente", + lt: "Ankstesnis", + lv: "Iepriekšējā", + mk: "Претходна", + nl: "Vorige", + no: "Tidligere", + pt: "Anterior", + ru: "Предыдущий", + sk: "Predchádzajúce", + sl: "Prejšnji", + sq: "E mëparshme", + sv: "Föregående", + tr: "Önceki", + uk: "Попередній" + }, + Finish: { + pl: "Zakończ", + en: "Finish", + be: "Аздабленне", + ca: "Acabat", + cs: "Dokončit", + da: "Finish", + de: "Finish", + el: "Τελειώνει", + es: "Acabado", + et: "Lõpeta", + fi: "Loppuun", + fr: "Finition", + hu: "Befejezés", + it: "Finitura", + lt: "Apdaila", + lv: "Apdare", + mk: "Заврши", + nl: "Afwerking", + no: "Ferdig", + pt: "Acabamento", + ru: "Отделка", + sk: "Povrch", + sl: "Zaključek", + sq: "Finish", + sv: "Avsluta", + tr: "Bitir", + uk: "Оздоблення" + } + }; + + function _t(s) { + return T[s][t[cur].language] || T[s]['en']; + } + + function step(n) { + cur = n; + $('.tourStep, .tourBg').remove(); + + if (!t[n]) { + return; + } + + $('body').append([ + '
', + '
', + '
', + !t[n].close ? '' : '', + '
', + t[n].content, + '
', + '', + '
', + '
' + ].join('')); + + var el = $('.tourStep') + .addClass(t[n].position) + .css({ + minWidth: 250 + }), + x = 0, + y = 0; + + if (t[n].element && !!t[n].element.length) { + var x1 = 1e6, + y1 = 1e6, + x2 = 0, + y2 = 0; + + t[n].element.each(function(k, v) { + var ofs = $(v).offset(); + x1 = Math.min(x1, ofs.left + t[n].forceCorrectionLeft); + y1 = Math.min(y1, ofs.top + t[n].forceCorrectionTop); + + x2 = Math.max(x2, ofs.left + t[n].forceCorrectionLeft + t[n].forceCorrectionWidth + + parseInt($(v).css('border-left-width')) + + parseInt($(v).css('padding-left')) + + $(v).width() + + parseInt($(v).css('padding-right')) + + parseInt($(v).css('border-right-width')) + ); + + y2 = Math.max(y2, ofs.top + t[n].forceCorrectionTop + t[n].forceCorrectionHeight + + parseInt($(v).css('border-top-width')) + + parseInt($(v).css('padding-top')) + + $(v).height() + + parseInt($(v).css('padding-bottom')) + + parseInt($(v).css('border-bottom-width')) + ); + }); + + switch (t[n].position) { + case 'top': + y = y1 - el.height(); + x = ((x1 + x2) >> 1) - (el.width() >> 1); + break; + + case 'right': + y = ((y1 + y2) >> 1) - (el.height()>> 1); + x = x2; + break; + + case 'left': + y = ((y1 + y2) >> 1) - (el.height()>> 1); + x = x1 - el.width(); + break; + + case 'bottom': + y = y2; + x = ((x1 + x2) >> 1) - (el.width() >> 1); + break; + }; + }; + + el + .css({ + position: 'absolute', + left: x, + top: y + }) + .show(); + + if (t[n].spotlight) { + var p = t[n].padding; + $('body').append(Array(5).join('
')); + + var pos = [ + { + bottom: 'auto', + height: y1 - p + }, + { + top: y2 + p, + height: $(document).height() - y2 - p + }, + { + right: 'auto', + bottom: 'auto', + top: y1 - p, + width: x1 - p, + height: 2 * p + y2 - y1 + }, + { + left: x2 + p, + bottom: 'auto', + top: y1 - p, + height: 2 * p + y2 - y1 + } + ]; + + $('.tourBg') + .css({ + position: 'absolute', + zIndex: 1000, + top: 0, + bottom: 0, + right: 0, + left: 0, + background: '#000', + opacity: 0.3 + }).each(function(k, v){ + $(v).css(pos[k]); + }); + } + + if (!!t[n].scroll) { + var my = ((Math.min(y, y1) + Math.max(y + el.height(), y2)) >> 1) - ($(window).height() >> 1), + mx = ((Math.min(x, x1) + Math.max(x + el.width(), x2)) >> 1) - ($(window).width() >> 1); + + $('html, body').animate({ + scrollTop: Math.max(0, Math.min(y, y1, my)), + scrollLeft: Math.max(0, Math.min(x, x1, mx)) + }); + } + + if (!n) { + $('.tourPrev').remove(); + } + + if (n > t.length - 2) { + $('.tourNext').text(_t('Finish')); + } + + $('.tourStep') + .on('click', '.tourNext:not([disabled])', Tour.next) + .on('click', '.tourPrev:not([disabled])', Tour.prev) + .on('click', '.tourClose:not([disabled])', Tour.close); + + (t[n].onstep || Tour.onstep || function(){})(t[n]); + } + + $(window).on('resize', function() { + if (!!Tour.onresize) { + Tour.onresize(); + } + }); + + return { + run: function(tour, options) { + try { + t = []; + cur = 0; + + o = { + close: true, + content: '', + language: 'en', + padding: 5, + position: 'right', + scroll: true, + spotlight: true, + forceCorrectionLeft: 0, + forceCorrectionTop: 0, + forceCorrectionWidth: 0, + forceCorrectionHeight: 0, + onstep: null, + }; + + for (var k in options) { + o[k] = options[k]; + } + + $(tour).each(function(k, v) { + for (var kk in o) { + v[kk] = v[kk] || o[kk]; + }; + + if (v.element && !!v.element.length) { + t.push(v); + } + }); + + step(cur); + + if (!!Tour.onstart) { + Tour.onstart(); + } + } catch(e) {} + }, + + next: function() { + step(cur + 1); + + if (cur == t.length) { + if (!!Tour.onfinish) { + Tour.onfinish(); + } + } + }, + + prev: function(){ + step(cur - 1); + }, + + current: function(){ + return cur; + }, + + close: function(){ + step(-1); + + if (!!Tour.onclose) { + Tour.onclose(); + } + }, + + onstart: null, + onfinish: null, + onclose: null, + onstep: null, + + onresize: function() { + var n = cur - 1; + step(-1); + cur = n; + + setTimeout(function() { + Tour.next(); + }, 20); + } + }; +})(); diff --git a/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.min.js b/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.min.js new file mode 100644 index 00000000..38939c05 --- /dev/null +++ b/static/ComSemApp/DKNotus-Tour-master/dknotus-tour.min.js @@ -0,0 +1,12 @@ +/*! + * DK Notus Tour JavaScript Library v1.2 + * https://github.com/DKNotusIT/DKNotus-Tour/ + * + * Copyright DK Notus and other contributors + * Released under the MIT license + * https://github.com/DKNotusIT/DKNotus-Tour/blob/master/LICENSE + * + * Date: 2018-03-17 + */ + + var Tour=function(){function _t(s){return T[s][t[cur].language]||T[s].en}function step(n){if(cur=n,$(".tourStep, .tourBg").remove(),t[n]){$("body").append(['
','
','
',t[n].close?'':"",'
',t[n].content,"
",'","
","
"].join(""));var el=$(".tourStep").addClass(t[n].position).css({minWidth:250}),x=0,y=0;if(t[n].element&&t[n].element.length){var x1=1e6,y1=1e6,x2=0,y2=0;switch(t[n].element.each(function(k,v){var ofs=$(v).offset();x1=Math.min(x1,ofs.left+t[n].forceCorrectionLeft),y1=Math.min(y1,ofs.top+t[n].forceCorrectionTop),x2=Math.max(x2,ofs.left+t[n].forceCorrectionLeft+t[n].forceCorrectionWidth+parseInt($(v).css("border-left-width"))+parseInt($(v).css("padding-left"))+$(v).width()+parseInt($(v).css("padding-right"))+parseInt($(v).css("border-right-width"))),y2=Math.max(y2,ofs.top+t[n].forceCorrectionTop+t[n].forceCorrectionHeight+parseInt($(v).css("border-top-width"))+parseInt($(v).css("padding-top"))+$(v).height()+parseInt($(v).css("padding-bottom"))+parseInt($(v).css("border-bottom-width")))}),t[n].position){case"top":y=y1-el.height(),x=(x1+x2>>1)-(el.width()>>1);break;case"right":y=(y1+y2>>1)-(el.height()>>1),x=x2;break;case"left":y=(y1+y2>>1)-(el.height()>>1),x=x1-el.width();break;case"bottom":y=y2,x=(x1+x2>>1)-(el.width()>>1)}}if(el.css({position:"absolute",left:x,top:y}).show(),t[n].spotlight){var p=t[n].padding;$("body").append(Array(5).join('
'));var pos=[{bottom:"auto",height:y1-p},{top:y2+p,height:$(document).height()-y2-p},{right:"auto",bottom:"auto",top:y1-p,width:x1-p,height:2*p+y2-y1},{left:x2+p,bottom:"auto",top:y1-p,height:2*p+y2-y1}];$(".tourBg").css({position:"absolute",zIndex:1e3,top:0,bottom:0,right:0,left:0,background:"#000",opacity:.3}).each(function(k,v){$(v).css(pos[k])})}if(t[n].scroll){var my=(Math.min(y,y1)+Math.max(y+el.height(),y2)>>1)-($(window).height()>>1),mx=(Math.min(x,x1)+Math.max(x+el.width(),x2)>>1)-($(window).width()>>1);$("html, body").animate({scrollTop:Math.max(0,Math.min(y,y1,my)),scrollLeft:Math.max(0,Math.min(x,x1,mx))})}n||$(".tourPrev").remove(),n>t.length-2&&$(".tourNext").text(_t("Finish")),$(".tourStep").on("click",".tourNext:not([disabled])",Tour.next).on("click",".tourPrev:not([disabled])",Tour.prev).on("click",".tourClose:not([disabled])",Tour.close),(t[n].onstep||Tour.onstep||function(){})(t[n])}}var o,cur,t=[];return T={step:{pl:"krok",en:"step",be:"крок",ca:"pas",cs:"krok",da:"trin",de:"Schritt",el:"βήμα",es:"paso",et:"samm",fi:"vaihe",fr:"étape",hu:"lépés",it:"passo",lt:"žingsnis",lv:"solis",mk:"чекор",nl:"stap",no:"trinn",pt:"passo",ru:"шаг",sk:"krok",sl:"korak",sq:"hapi",sv:"steg",tr:"adım",uk:"крок"},Next:{pl:"Następny",en:"Next",be:"Далей",ca:"Següent",cs:"Další",da:"Næste",de:"Weiter",el:"Την επόμενη",es:"Siguiente",et:"Järgmine",fi:"Seuraava",fr:"Prochaine",hu:"Következő",it:"Accanto",lt:"Kitas",lv:"Nākamā",mk:"Следна",nl:"Volgende",no:"Neste",pt:"Próximo",ru:"Далее",sk:"Ďalej",sl:"Naprej",sq:"Tjetër",sv:"Nästa",tr:"Gelecek",uk:"Далі"},Previous:{pl:"Poprzedni",en:"Previous",be:"Папярэдні",ca:"Anteriors",cs:"Předchozí",da:"Tidligere",de:"Vorherige",el:"Προηγούμενο",es:"Anterior",et:"Eelmine",fi:"Edellinen",fr:"Précédente",hu:"Előző",it:"Precedente",lt:"Ankstesnis",lv:"Iepriekšējā",mk:"Претходна",nl:"Vorige",no:"Tidligere",pt:"Anterior",ru:"Предыдущий",sk:"Predchádzajúce",sl:"Prejšnji",sq:"E mëparshme",sv:"Föregående",tr:"Önceki",uk:"Попередній"},Finish:{pl:"Zakończ",en:"Finish",be:"Аздабленне",ca:"Acabat",cs:"Dokončit",da:"Finish",de:"Finish",el:"Τελειώνει",es:"Acabado",et:"Lõpeta",fi:"Loppuun",fr:"Finition",hu:"Befejezés",it:"Finitura",lt:"Apdaila",lv:"Apdare",mk:"Заврши",nl:"Afwerking",no:"Ferdig",pt:"Acabamento",ru:"Отделка",sk:"Povrch",sl:"Zaključek",sq:"Finish",sv:"Avsluta",tr:"Bitir",uk:"Оздоблення"}},$(window).on("resize",function(){Tour.onresize&&Tour.onresize()}),{run:function(tour,options){try{t=[],cur=0,o={close:!0,content:"",language:"en",padding:5,position:"right",scroll:!0,spotlight:!0,forceCorrectionLeft:0,forceCorrectionTop:0,forceCorrectionWidth:0,forceCorrectionHeight:0,onstep:null};for(var k in options)o[k]=options[k];$(tour).each(function(k,v){for(var kk in o)v[kk]=v[kk]||o[kk];v.element&&v.element.length&&t.push(v)}),step(cur),Tour.onstart&&Tour.onstart()}catch(e){}},next:function(){step(cur+1),cur==t.length&&Tour.onfinish&&Tour.onfinish()},prev:function(){step(cur-1)},current:function(){return cur},close:function(){step(-1),Tour.onclose&&Tour.onclose()},onstart:null,onfinish:null,onclose:null,onstep:null,onresize:function(){var n=cur-1;step(-1),cur=n,setTimeout(function(){Tour.next()},20)}}}(); \ No newline at end of file diff --git a/static/ComSemApp/DKNotus-Tour-master/examples.html b/static/ComSemApp/DKNotus-Tour-master/examples.html new file mode 100644 index 00000000..52867654 --- /dev/null +++ b/static/ComSemApp/DKNotus-Tour-master/examples.html @@ -0,0 +1,768 @@ + + + + + + DK Notus Tour - Examples + + + + + + +
+ + + + +
+
+

+ This compact solution for guided tours has + 27 languages support. + It requires only two very common dependencies: + jQuery and Bootstrap. + Also has useful features like auto scroll + and "spotlight". + We hope you enjoy it. +

+ +
+ DK Notus Tour +
+ +

+ We tried to keep all data regarding usage as short as possible. +

+ +

1. Features

+ +

+ Features that we considerble important: +

+ +
+
small requirements
+
only jQuery and Bootstrap;
+ +
simple usage
+
one function for common usage - yes, it's that simple;
+ +
events
+
for advanced programmers usage;
+ +
scroll
+
and some more useful features;
+ +
multi elem. selection
+
you can point more then one element for one tour step;
+ +
translations
+
languages support.
+
+ +

2. Simple use case

+ +

Lets start with two step tour for elements below:

+ + + + + +

+ First of all we need to include two common libraries + jQuery and Bootstrap. + You ca use some CDN for that. +

+ +
+
  <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
+  <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
+
+ +

+ Then it's time tour library dknotus-tour.js + or dknotus-tour.min.js. +

+ +
+
  <script src="dknotus-tour.js"></script>
+
+ +

+ Finally we can define our own tour and run it with + Tour.run(). Yes, it's that simple. +

+ + + +
+
+  $(function(){
+    $('#simpleBtn').click(function(){
+      Tour.run([
+        {
+          element: $('#btn1'),
+          content: 'first btn'
+        },
+        {
+          element: $('#btn2'),
+          content: 'and the second one<br>description might be <strong>HTML</strong>'
+        },
+      ]);
+    });
+  });
+            
+
+ +

3. Different tour positions

+ + + + + + + +
+
+  $(function(){
+    $('#positionsBtn').click(function(){
+      Tour.run([
+        {
+          element: $('#posBtn'),
+          content: 'by default tour is on the right'
+        },
+        {
+          element: $('#posBtn'),
+          content: 'but it can be on top',
+          position: 'top'
+        },
+        {
+          element: $('#posBtn'),
+          content: 'bottom',
+          position: 'bottom'
+        },
+        {
+          element: $('#posBtn'),
+          content: 'and finally on the left',
+          position: 'left'
+        }
+      ]);
+    });
+  });
+
+ +

4. Global and local parameters

+ +

+ Tour may be run with two parameters: tour description (mandatory) + and global options (optional) Tour.run(tourDescription, + options). If for some tour hint some parameter is not set, + then if it's possible it's taken from options. +

+ +

+ Possible parameters for hints descriptions and for global options +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDefault valueDescription
elementnone + jQuery element (might be more then one), + if it's not set then hint is skipped. +
contentempty stringIt's for contents of particular hints.
closetrueDefines if close button should be shown.
languageen + Defines interface language. Available languages: +
+
en
+
English (default)
+ +
pl
+
Polish
+ +
be
+
Belarusian
+ +
ca
+
Catalan
+ +
cs
+
Czech
+ +
da
+
Danish
+ +
de
+
German
+ +
el
+
Greek
+ +
es
+
Spanish
+ +
et
+
Estonian
+ +
fi
+
Finnish
+ +
fr
+
French
+ +
hu
+
Hungarian
+ +
it
+
Italian
+ +
lt
+
Lithuanian
+ +
lv
+
Latvian
+ +
mk
+
Macedonian
+ +
nl
+
Dutch
+ +
no
+
Norwegian
+ +
pt
+
Portuguese
+ +
ru
+
Russian
+ +
sk
+
Slovak
+ +
sl
+
Slovenian
+ +
sq
+
Albanian
+ +
sv
+
Swedish
+ +
tr
+
Turkish
+ +
uk
+
Ukrainian
+
+
padding5 + Extra space around tour exposed elements. + (Has only sense when spotlight option is true). +
positionright + Determines where hint should be shown relativly to element + it describes.
+ Possible values: right, left, top and bottom. +
scrolltrue + If true then scrolls window so selected element + and hint would be as close as possible to the view center. +
spotlighttrue + If true then covers everything except selected element + and hint with shadow. +
forceCorrectionLeft0 + Useful if for some reason left offset needs to be modified. +
forceCorrectionTop0 + Useful if for some reason top offset needs to be modified. +
forceCorrectionWidth0 + Useful if for some reason width needs to be modified. +
forceCorrectionHeight0 + Useful if for some reason height needs to be modified. +
+ +

+ All above options can be used for both: single hint description + and for global options. With global options previous example + can be writen like: +

+ +
+
+  $(function(){
+    $('#positionsShorterBtn').click(function(){
+      var globalOptions = {
+        element: $('#posBtn')
+      };
+
+      var tourDescription = [
+        {
+          content: 'by default tour is on the right'
+        },
+        {
+          content: 'but it can be on top',
+          position: 'top'
+        },
+        {
+          content: 'bottom',
+          position: 'bottom'
+        },
+        {
+          content: 'and finally on the left',
+          position: 'left'
+        }
+      ];
+
+      Tour.run(tourDescription, globalOptions);
+    });
+  });
+
+ + + + + +

5. Events example

+ +

+ There are four events that can be used by developers: +

+ +
+
onstart()
+
Triggered when new tour starts ( Tour.run() ).
+ +
onfinish()
+
Triggered when Finish button is clicked.
+ +
onclose()
+
+ Triggered when Close button is pressed + ( Tour.close() ). +
+ +
onstep( currentStep )
+
+ Triggered on every step shown + ( Tour.next() or Tour.prev() ). +
+ +
onresize
+
By default this one is set.
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+ + + + + +
+
+  $(function(){
+    $('#eventsBtn').click(function(){
+      Tour.onstart = function(){
+        console.log('We started!');
+      };
+
+      Tour.onfinish = function(){
+        console.log('The End');
+      };
+
+      Tour.onclose = function(){
+        console.log('Tour interupted');
+      };
+
+      Tour.onstep = function(currentStep){
+        console.log('"That\'s one small step for a man ..."');
+        console.log(currentStep);
+      };
+
+      Tour.run([
+        {
+          element: $('#eventBtn1').add('#eventBtn3'),
+          content: 'You prefer photos?',
+          position: 'top'
+        },
+        {
+          element: $('#eventBtn3').add('#eventBtn4'),
+          content: 'or videos?',
+          onstep: function(currentStep) {
+            console.log('Events defined in step, overwrites global definition');
+          }
+        }
+      ]);
+    });
+  });
+
+ +

6. Tour interface

+ +

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Tour.run( tourDescription, globlOptions )Function for running Tour;
Tour.next()Goes to next tour step;
Tour.prev()Goes to previous tour step;
Tour.close()Interrupts tour and closes it;
Tour.current()Returns current step description.
+ +

Events

+ +

+ By default all except onresize are set to null. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
EventDescription
Tour.onstart() + Triggered when new tour starts ( Tour.run() ); +
Tour.onfinish()Triggered when Finish button is clicked;
Tour.onclose() + Triggered when Close button is pressed + ( Tour.close() ); +
Tour.onstep( currentStep ) + Triggered on every step shown + ( Tour.next() or Tour.prev() ); +
Tour.onresize()By default this one is set.
+ +

7. Contact

+ + Jan Doleczek + +
+ + No animals were harmed during development. + + + + DK Notus 2016 + + +
+ + +
+
+ +