Compare commits
59 Commits
ccf02f2e16
...
working
| Author | SHA1 | Date | |
|---|---|---|---|
| 807d104d06 | |||
| 053aa4bd5a | |||
| 40e24501f6 | |||
| 522d10f422 | |||
| 789d49a2c9 | |||
| 86c5f3fdea | |||
| 26c28cd0da | |||
| e1b814da4f | |||
| edcd32db47 | |||
| e253586467 | |||
| 728c282a3d | |||
| 23e6ee55c6 | |||
| 52db4cc0fb | |||
| 2702ce3c3c | |||
| ab27d70946 | |||
| 73fc70917c | |||
| 8898f7dfb8 | |||
| aa2fa44207 | |||
| 15ae63d48b | |||
| 0d92d281e1 | |||
| 38e9c9f7ed | |||
| 3ca3307528 | |||
| 666a92ecd0 | |||
| ecf5531026 | |||
| 8edfd3ef2f | |||
| 5eed494c16 | |||
| c4e312662c | |||
| 785b4c4ff5 | |||
| c630f4e54b | |||
| 664c5bc1af | |||
| 428a9b0b44 | |||
| f4dd20e76d | |||
| 8a1c7aff42 | |||
| 91802c2ecd | |||
| 3c37288476 | |||
| 5ad3676b7f | |||
| 4c6ec411b1 | |||
| f0526555f1 | |||
| ceb5e0bec9 | |||
| d758e97001 | |||
| cdbb57d50d | |||
| 73127d9950 | |||
| 7e331ba91b | |||
| 56a20f4465 | |||
| 3eac9d64cb | |||
| 54e805ec50 | |||
| b1e939adeb | |||
| dfb37e4a86 | |||
| 63ffaf02a6 | |||
| 645fac2e9d | |||
| 3918d81495 | |||
| a75efd7a5f | |||
| 3e482d2e49 | |||
| f4bb2959e6 | |||
| 11f051c7d9 | |||
| 18ec49903b | |||
| 46f5979aef | |||
| 2f6a42d39a | |||
| 75202fe7a5 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,6 +5,10 @@ __pycache__/
|
|||||||
|
|
||||||
instance/
|
instance/
|
||||||
|
|
||||||
|
uploads/
|
||||||
|
zip_exports/
|
||||||
|
exports/
|
||||||
|
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
.coverage
|
.coverage
|
||||||
htmlcov/
|
htmlcov/
|
||||||
|
|||||||
88
README.md
88
README.md
@@ -1,93 +1,19 @@
|
|||||||
# masterproject
|
# masterproject
|
||||||
|
|
||||||
|
|
||||||
|
build the dockerfile with: docker build -t slaeforms .
|
||||||
|
|
||||||
## Getting started
|
run the container on port 8000 with: docker run -d -p 8000:8000 slaeforms
|
||||||
|
|
||||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
export the container: docker save -o slaeforms.tar slaforms:latest
|
||||||
|
|
||||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
|
||||||
|
|
||||||
## Add your files
|
|
||||||
|
|
||||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
|
||||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
|
||||||
|
|
||||||
```
|
Pushing code from desktop to leafblade:
|
||||||
cd existing_repo
|
|
||||||
git remote add origin https://gitlab.com/JanDickmann/masterproject.git
|
|
||||||
git branch -M main
|
|
||||||
git push -uf origin main
|
|
||||||
```
|
|
||||||
|
|
||||||
## Integrate with your tools
|
See remotes: git remote -v
|
||||||
|
|
||||||
- [ ] [Set up project integrations](https://gitlab.com/JanDickmann/masterproject/-/settings/integrations)
|
git push leafblade working //push working branch
|
||||||
|
|
||||||
## Collaborate with your team
|
then create a pull request on leafblade and merge everything
|
||||||
|
|
||||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
|
||||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
|
||||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
|
||||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
|
||||||
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
|
||||||
|
|
||||||
## Test and Deploy
|
|
||||||
|
|
||||||
Use the built-in continuous integration in GitLab.
|
|
||||||
|
|
||||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
|
||||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
|
||||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
|
||||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
|
||||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
# Editing this README
|
|
||||||
|
|
||||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
|
||||||
|
|
||||||
## Suggestions for a good README
|
|
||||||
|
|
||||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
|
||||||
|
|
||||||
## Name
|
|
||||||
Choose a self-explaining name for your project.
|
|
||||||
|
|
||||||
## Description
|
|
||||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
|
||||||
|
|
||||||
## Badges
|
|
||||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
|
||||||
|
|
||||||
## Visuals
|
|
||||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
|
||||||
|
|
||||||
## Support
|
|
||||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
State if you are open to contributions and what your requirements are for accepting them.
|
|
||||||
|
|
||||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
|
||||||
|
|
||||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
|
||||||
|
|
||||||
## Authors and acknowledgment
|
|
||||||
Show your appreciation to those who have contributed to the project.
|
|
||||||
|
|
||||||
## License
|
|
||||||
For open source projects, say how it is licensed.
|
|
||||||
|
|
||||||
## Project status
|
|
||||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
|
||||||
239
slaeforms/app.py
239
slaeforms/app.py
@@ -11,13 +11,13 @@ import uuid
|
|||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy import select, join
|
from sqlalchemy import select, join
|
||||||
from sqlalchemy.orm import DeclarativeBase
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
from flask_wtf.csrf import CSRFProtect
|
#from flask_wtf.csrf import CSRFProtect
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
import hashlib
|
||||||
|
|
||||||
random_order = True
|
# activate environment: cd C:\...\...\....\...\Code\SLAEForms Testing\.venv\Scripts\
|
||||||
# activate environment: cd C:\Users\Jan\Google Drive\Master Stuff\Code\SLAEForms Testing\.venv\Scripts\
|
|
||||||
# then this: activate
|
# then this: activate
|
||||||
|
|
||||||
#SETUP--------------------------------------------------
|
#SETUP--------------------------------------------------
|
||||||
@@ -33,6 +33,7 @@ app = Flask(__name__)
|
|||||||
# configure the database, give it a path (it will be in the instances folder)
|
# configure the database, give it a path (it will be in the instances folder)
|
||||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database.db"
|
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database.db"
|
||||||
app.config["PERMANENT_SESSION_LIFETIME"] = 10800 #3 Stunden, 10800 sekunden
|
app.config["PERMANENT_SESSION_LIFETIME"] = 10800 #3 Stunden, 10800 sekunden
|
||||||
|
app.config['MAX_CONTENT_LENGTH'] = 22 * 1000 * 1000 # try and fix video upload not working
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
|
||||||
#set the secret key (TODO change this for final deployment)
|
#set the secret key (TODO change this for final deployment)
|
||||||
@@ -40,6 +41,10 @@ app.secret_key = b"29fe9e8edd407c5491d4f1c05632d9fa33e26ed8734a3f5e080ebac3772a5
|
|||||||
|
|
||||||
UPLOAD_FOLDER = 'uploads'
|
UPLOAD_FOLDER = 'uploads'
|
||||||
EXPORT_FOLDER = 'exports'
|
EXPORT_FOLDER = 'exports'
|
||||||
|
PASSWORD = 'd5aff9fc14d1f20f4ccddaa8b4f2c1765228b74ed0b1dfb868bf1064e0d655e2'
|
||||||
|
CONFIGFILE = 'userstudy1.json'
|
||||||
|
# CONFIGFILE = 'test.json'
|
||||||
|
# CONFIGFILE = 'default.json'
|
||||||
|
|
||||||
#csrf = CSRFProtect(app) #enable CSRF protection globally
|
#csrf = CSRFProtect(app) #enable CSRF protection globally
|
||||||
|
|
||||||
@@ -53,6 +58,7 @@ class User(db.Model):
|
|||||||
device_id = db.Column("device_id",db.UUID(as_uuid=True), nullable=False)
|
device_id = db.Column("device_id",db.UUID(as_uuid=True), nullable=False)
|
||||||
question_order = db.Column("question_order",db.String(60))
|
question_order = db.Column("question_order",db.String(60))
|
||||||
date_created = db.Column("date_created",db.DateTime, default=datetime.today()) # todo test if this default works
|
date_created = db.Column("date_created",db.DateTime, default=datetime.today()) # todo test if this default works
|
||||||
|
form_completed = db.Column("form_completed",db.Boolean, default=False)
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return "<User %r>" % self.user_id
|
return "<User %r>" % self.user_id
|
||||||
|
|
||||||
@@ -68,7 +74,7 @@ except SQLAlchemyError as e:
|
|||||||
#open, parse and execute json file
|
#open, parse and execute json file
|
||||||
|
|
||||||
#open the json file with the config
|
#open the json file with the config
|
||||||
configfile = open("default.json", encoding='utf-8') #todo replace with other name
|
configfile = open(CONFIGFILE, encoding='utf-8') #todo replace with other name
|
||||||
#convert it to dict
|
#convert it to dict
|
||||||
config = json.load(configfile)
|
config = json.load(configfile)
|
||||||
configfile.close()
|
configfile.close()
|
||||||
@@ -131,7 +137,7 @@ except SQLAlchemyError as e:
|
|||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
#actual page logic with start, form and send
|
#actual page logic with start, form and send
|
||||||
|
|
||||||
@app.route("/popuptest", methods=["GET"])
|
#@app.route("/popuptest", methods=["GET"])
|
||||||
def popuptest():
|
def popuptest():
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
@@ -149,6 +155,7 @@ def startpage():
|
|||||||
session["agreed_to_tos"] = False
|
session["agreed_to_tos"] = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
#right now if a user that has an active session goes to the startpage again and accepts tos
|
#right now if a user that has an active session goes to the startpage again and accepts tos
|
||||||
#it will just start another session and discard the previous session
|
#it will just start another session and discard the previous session
|
||||||
@@ -178,19 +185,21 @@ def startpage():
|
|||||||
print(session["block_names"])
|
print(session["block_names"])
|
||||||
|
|
||||||
for name in block_names:
|
for name in block_names:
|
||||||
if config[name]["type"] == "TaskTemplate" and ("stimuli" in current_block):
|
print("block: ",name)
|
||||||
|
if config[name]["type"] == "TaskTemplate" and ("stimuli" in config[name]):
|
||||||
match config[name]["stimuli"]["type"]:
|
match config[name]["stimuli"]["type"]:
|
||||||
case "single_video":
|
case "single_video":
|
||||||
order = list(config[name]["stimuli"]["list"]) # order = list of simuli keys
|
order = list(config[name]["stimuli"]["list"]) # order = list of simuli keys
|
||||||
print("order: ",order)
|
print("order: ",order)
|
||||||
|
if "order" in config[name]["stimuli"]:
|
||||||
if config[name]["stimuli"]["order"] == "random":
|
if config[name]["stimuli"]["order"] == "random":
|
||||||
random.shuffle(order) #in random order
|
random.shuffle(order) #in random order
|
||||||
session["block_order"][name] = order
|
session["block_order"][name] = order
|
||||||
case "double_video":
|
case "double_video":
|
||||||
order = [] # order = list of stimuli keys
|
order = [] # order = list of stimuli keys
|
||||||
list_1 = list(current_block["stimuli"]["list_1"])
|
list_1 = list(config[name]["stimuli"]["list_1"])
|
||||||
list_2 = list(current_block["stimuli"]["list_2"])
|
list_2 = list(config[name]["stimuli"]["list_2"])
|
||||||
for i in range(len(list(current_block["stimuli"]["list_1"]))):
|
for i in range(len(list(config[name]["stimuli"]["list_1"]))):
|
||||||
order.append((list_1[i], list_2[i]))
|
order.append((list_1[i], list_2[i]))
|
||||||
print("order: ",order)
|
print("order: ",order)
|
||||||
#TODO random is not implemented here
|
#TODO random is not implemented here
|
||||||
@@ -213,11 +222,12 @@ def startpage():
|
|||||||
user_id = new_user_id
|
user_id = new_user_id
|
||||||
question_order = str(session["block_order"])
|
question_order = str(session["block_order"])
|
||||||
date = datetime.today()
|
date = datetime.today()
|
||||||
new_user = User(user_id=user_id, device_id=device_id,question_order=question_order,date_created = date) #,question_order=question_order
|
new_user = User(user_id=user_id, device_id=device_id,question_order=question_order,date_created = date,form_completed=False) #,question_order=question_order
|
||||||
|
|
||||||
db.session.add(new_user)
|
db.session.add(new_user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
print("block order: {order}".format(order=session["block_order"]))
|
print("block order: {order}".format(order=session["block_order"]))
|
||||||
try:
|
try:
|
||||||
db.session.add(new_user)
|
db.session.add(new_user)
|
||||||
@@ -228,9 +238,26 @@ def startpage():
|
|||||||
return redirect("/form")
|
return redirect("/form")
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"teststartpage.html"
|
"startpage.html"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.route("/endpage")
|
||||||
|
def endpage():
|
||||||
|
print("Form is done, sent to endpage")
|
||||||
|
return render_template("endpage.html")
|
||||||
|
|
||||||
|
@app.route("/datenschutz")
|
||||||
|
def datenschutz():
|
||||||
|
return render_template("datenschutz.html")
|
||||||
|
|
||||||
|
@app.route("/impressum")
|
||||||
|
def impressum():
|
||||||
|
return render_template("impressum.html")
|
||||||
|
|
||||||
|
@app.route("/studytest")
|
||||||
|
def studytest():
|
||||||
|
return render_template("studytest.html")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/form")
|
@app.route("/form")
|
||||||
def form():
|
def form():
|
||||||
@@ -248,11 +275,15 @@ def form():
|
|||||||
#print("current Blockname: {blockname}, current block index: {blockindex}, current stim index: {stimulusindex}".format(blockname=session["current_block_name"],
|
#print("current Blockname: {blockname}, current block index: {blockindex}, current stim index: {stimulusindex}".format(blockname=session["current_block_name"],
|
||||||
# blockindex=session["current_block_index"],
|
# blockindex=session["current_block_index"],
|
||||||
# stimulusindex=session["current_stimulus_index"] ) )
|
# stimulusindex=session["current_stimulus_index"] ) )
|
||||||
|
infovideo = None
|
||||||
|
if "infovideo" in current_block:
|
||||||
|
infovideo = current_block["infovideo"]
|
||||||
|
|
||||||
# erster Fall: SinglePage
|
# erster Fall: SinglePage
|
||||||
if current_block["type"] == "SinglePage":
|
if current_block["type"] == "SinglePage":
|
||||||
return render_template(current_block["template"])
|
return render_template(current_block["template"])
|
||||||
|
|
||||||
|
|
||||||
#zweiter Fall, empty TaskTemplate
|
#zweiter Fall, empty TaskTemplate
|
||||||
if current_block["type"] == "TaskTemplate" and current_block["stimuli"]["type"] == "empty":
|
if current_block["type"] == "TaskTemplate" and current_block["stimuli"]["type"] == "empty":
|
||||||
current_block_order = session["block_order"][session["current_block_name"]]
|
current_block_order = session["block_order"][session["current_block_name"]]
|
||||||
@@ -264,7 +295,8 @@ def form():
|
|||||||
stimuli=current_block_stimuli,
|
stimuli=current_block_stimuli,
|
||||||
stimulus_type=stimulus_type,
|
stimulus_type=stimulus_type,
|
||||||
current_stimulus=current_stimulus,
|
current_stimulus=current_stimulus,
|
||||||
questions=current_block["questions"]
|
questions=current_block["questions"],
|
||||||
|
infovideo=infovideo
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -293,7 +325,8 @@ def form():
|
|||||||
stimulus_type=stimulus_type,
|
stimulus_type=stimulus_type,
|
||||||
current_stimulus=current_stimulus,
|
current_stimulus=current_stimulus,
|
||||||
stimulus_configuration=stimulus_configuration,
|
stimulus_configuration=stimulus_configuration,
|
||||||
questions=current_block["questions"]
|
questions=current_block["questions"],
|
||||||
|
infovideo=infovideo
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -333,7 +366,7 @@ def sendpage():
|
|||||||
video = request.files['recordedVideo']
|
video = request.files['recordedVideo']
|
||||||
formatted_date = date.strftime("%Y.%m.%d %H-%M-%S")
|
formatted_date = date.strftime("%Y.%m.%d %H-%M-%S")
|
||||||
print("date: ", date)
|
print("date: ", date)
|
||||||
video_name = str(session_user_id) + "_" + session["current_block_name"] + "_" + session["current_stimulus_name"] + "_" + str(formatted_date) + ".webm"
|
video_name = str(session_user_id) + "_" + session["current_block_name"] + "_" + str(session["current_stimulus_name"]) + "_" + str(formatted_date) + ".webm"
|
||||||
path = os.path.join(UPLOAD_FOLDER, video_name)
|
path = os.path.join(UPLOAD_FOLDER, video_name)
|
||||||
print("path: ",path)
|
print("path: ",path)
|
||||||
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||||||
@@ -344,7 +377,19 @@ def sendpage():
|
|||||||
setattr(new_entry, "video_upload", video_name)
|
setattr(new_entry, "video_upload", video_name)
|
||||||
|
|
||||||
|
|
||||||
for key, value in request.form.items():
|
# TODO maybe find a prettier solution, this handeles multiple choice now, so the fact that there can be
|
||||||
|
# multiple keys that are the same in the form data, but I want to bring them together to 1 key value pair
|
||||||
|
form_data = {}
|
||||||
|
for key in request.form:
|
||||||
|
values = request.form.getlist(key)
|
||||||
|
|
||||||
|
# If there's more than one value for the key, join them with commas
|
||||||
|
if len(values) > 1:
|
||||||
|
form_data[key] = ','.join(map(str, values)) # Join multiple values into a single comma-separated string
|
||||||
|
else:
|
||||||
|
form_data[key] = values[0] # If only one value, store it directly
|
||||||
|
|
||||||
|
for key, value in form_data.items():
|
||||||
print("hasattr key: ", key)
|
print("hasattr key: ", key)
|
||||||
if hasattr(new_entry, key):
|
if hasattr(new_entry, key):
|
||||||
print("key exists: ", key)
|
print("key exists: ", key)
|
||||||
@@ -358,17 +403,20 @@ def sendpage():
|
|||||||
print("Error occurred: {e}".format(e=str(e)))
|
print("Error occurred: {e}".format(e=str(e)))
|
||||||
return "There was a problem while adding the response to the Database"
|
return "There was a problem while adding the response to the Database"
|
||||||
|
|
||||||
# handle possible Video that was send
|
|
||||||
if 'recordedVideo' in request.files:
|
|
||||||
video = request.files['recordedVideo']
|
|
||||||
formatted_date = date.strftime("%Y.%m.%d %H-%M-%S")
|
|
||||||
print("date: ", date)
|
|
||||||
video_name = str(session_user_id) + "_" + session["current_block_name"] + "_" + session["current_stimulus_name"] + "_" + str(formatted_date) + ".webm"
|
|
||||||
path = os.path.join(UPLOAD_FOLDER, video_name)
|
|
||||||
print("path: ",path)
|
|
||||||
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
|
||||||
video.save(path)
|
|
||||||
|
|
||||||
|
if (session["current_block_index"] == session["number_of_blocks"]-1) and (session["current_stimulus_index"] >= session["number_of_stimuli"]-1):
|
||||||
|
#update the database entry, the form is completed
|
||||||
|
user = db.session.query(User).filter_by(user_id=session["slaeform_user_id"]).one()
|
||||||
|
user.form_completed = True
|
||||||
|
print("updated db entry for form_completed")
|
||||||
|
# This user is done, so we can remove it from the session
|
||||||
|
session.pop("slaeform_user_id")
|
||||||
|
try:
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
print("Error occurred: {e}".format(e=str(e)))
|
||||||
|
return "There was a problem while updating the user"
|
||||||
|
return redirect("/endpage")
|
||||||
|
|
||||||
# Now move to the next stimulus or block
|
# Now move to the next stimulus or block
|
||||||
update_session()
|
update_session()
|
||||||
@@ -376,16 +424,19 @@ def sendpage():
|
|||||||
return redirect("/form")
|
return redirect("/form")
|
||||||
|
|
||||||
def update_session():
|
def update_session():
|
||||||
|
print("update session")
|
||||||
if "stimuli" in config[session["current_block_name"]]:
|
if "stimuli" in config[session["current_block_name"]]:
|
||||||
# if there are stimuli in this block
|
# if there are stimuli in this block
|
||||||
if session["current_stimulus_index"] < session["number_of_stimuli"]-1:
|
if session["current_stimulus_index"] < session["number_of_stimuli"]-1:
|
||||||
|
print("there are still stimuli left")
|
||||||
# if there are still stimuli left, keep going through them
|
# if there are still stimuli left, keep going through them
|
||||||
session["current_stimulus_index"] += 1
|
session["current_stimulus_index"] += 1
|
||||||
# set the name of the current stimulus
|
# set the name of the current stimulus
|
||||||
session["current_stimulus_name"] = session["block_order"][session["current_block_name"]][session["current_stimulus_index"]]
|
session["current_stimulus_name"] = session["block_order"][session["current_block_name"]][session["current_stimulus_index"]]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
print("here are no stimuli left")
|
||||||
|
session["number_of_stimuli"] = 0
|
||||||
# if there are no stimuli left..
|
# if there are no stimuli left..
|
||||||
if(session["current_block_index"] < session["number_of_blocks"]-1):
|
if(session["current_block_index"] < session["number_of_blocks"]-1):
|
||||||
# go to next block if possible
|
# go to next block if possible
|
||||||
@@ -393,7 +444,7 @@ def update_session():
|
|||||||
session["current_block_name"] = session["block_names"][session["current_block_index"]]
|
session["current_block_name"] = session["block_names"][session["current_block_index"]]
|
||||||
session["current_stimulus_index"] = 0
|
session["current_stimulus_index"] = 0
|
||||||
if "stimuli" in config[session["current_block_name"]]:
|
if "stimuli" in config[session["current_block_name"]]:
|
||||||
session["number_of_stimuli"] = len(list(config[session["current_block_name"]]["stimuli"]["list"]))
|
session["number_of_stimuli"] = len(session["block_order"][session["current_block_name"]])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# if there arent any stimuli, go to the next block
|
# if there arent any stimuli, go to the next block
|
||||||
@@ -403,18 +454,39 @@ def update_session():
|
|||||||
session["current_block_index"] += 1
|
session["current_block_index"] += 1
|
||||||
session["current_block_name"] = session["block_names"][session["current_block_index"]]
|
session["current_block_name"] = session["block_names"][session["current_block_index"]]
|
||||||
|
|
||||||
if "stimuli" in config[session["current_block_name"]]:
|
#set values for the new block
|
||||||
|
current_block = config[session["current_block_name"]]
|
||||||
|
|
||||||
|
if "stimuli" in current_block:
|
||||||
# set the name of the current stimulus
|
# set the name of the current stimulus
|
||||||
session["current_stimulus_name"] = session["block_order"][session["current_block_name"]][session["current_stimulus_index"]]
|
session["current_stimulus_name"] = session["block_order"][session["current_block_name"]][session["current_stimulus_index"]]
|
||||||
|
|
||||||
if (session["current_block_index"] == session["number_of_blocks"]-1) and (session["current_stimulus_index"] >= session["number_of_stimuli"]-1):
|
# if the block has stimuli, get how many
|
||||||
session.pop("slaeform_user_id")
|
if current_block["stimuli"]["type"] == "single_video" or current_block["stimuli"]["type"] == "empty":
|
||||||
print("---Session updated---")
|
session["number_of_stimuli"] = len(list(current_block["stimuli"]["list"]))
|
||||||
|
elif current_block["stimuli"]["type"] == "double_video":
|
||||||
|
session["number_of_stimuli"] = len(list(current_block["stimuli"]["list_1"]))
|
||||||
|
|
||||||
|
print("---Session updated-----------------------------------------------")
|
||||||
print("current_block_index / number_of_blocks: {current_block_index} / {number_of_blocks}".format(current_block_index=session["current_block_index"],number_of_blocks=session["number_of_blocks"]))
|
print("current_block_index / number_of_blocks: {current_block_index} / {number_of_blocks}".format(current_block_index=session["current_block_index"],number_of_blocks=session["number_of_blocks"]))
|
||||||
print("current_block_name: ", session["current_block_name"])
|
print("current_block_name: ", session["current_block_name"])
|
||||||
print("current_stimulus_index: ", session["current_stimulus_index"])
|
print("current_stimulus_index: ", session["current_stimulus_index"])
|
||||||
print("Current number_of_stimuli: ", session["number_of_stimuli"])
|
print("Current number_of_stimuli: ", session["number_of_stimuli"])
|
||||||
|
|
||||||
|
#@app.route("/update")
|
||||||
|
def update():
|
||||||
|
|
||||||
|
print("Current Session: ",session)
|
||||||
|
try:
|
||||||
|
user = db.session.query(User).filter_by(user_id=session["slaeform_user_id"]).one()
|
||||||
|
user.form_completed = True
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
print("Error occurred: {e}".format(e=str(e)))
|
||||||
|
return "There was a problem while updating the user"
|
||||||
|
|
||||||
|
return "db entry updated!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Database stuff------------------------------------------------------------------------------
|
# Database stuff------------------------------------------------------------------------------
|
||||||
@@ -439,6 +511,9 @@ def create_all_csvs():
|
|||||||
# export CSV
|
# export CSV
|
||||||
@app.route("/export_all_tables")
|
@app.route("/export_all_tables")
|
||||||
def export_all_tables():
|
def export_all_tables():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
|
|
||||||
create_all_csvs()
|
create_all_csvs()
|
||||||
|
|
||||||
with ZipFile('zip_exports/all_tables.zip', 'w') as zipf: #no compression, need to add zipfile.ZIP_DEFLATED for compression
|
with ZipFile('zip_exports/all_tables.zip', 'w') as zipf: #no compression, need to add zipfile.ZIP_DEFLATED for compression
|
||||||
@@ -446,14 +521,27 @@ def export_all_tables():
|
|||||||
|
|
||||||
return send_file("zip_exports/all_tables.zip", as_attachment=False, download_name="all_tables.zip")
|
return send_file("zip_exports/all_tables.zip", as_attachment=False, download_name="all_tables.zip")
|
||||||
|
|
||||||
|
# export Database
|
||||||
|
@app.route("/export_db")
|
||||||
|
def export_db():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
|
|
||||||
|
with ZipFile('zip_exports/db.zip', 'w') as zipf: #no compression, need to add zipfile.ZIP_DEFLATED for compression
|
||||||
|
zipdir('instance/', zipf)
|
||||||
|
|
||||||
|
return send_file("zip_exports/db.zip", as_attachment=False, download_name="db.zip")
|
||||||
|
|
||||||
# export CSV
|
# export CSV
|
||||||
@app.route("/export_all_videos")
|
@app.route("/export_all_videos")
|
||||||
def export_all_videos():
|
def export_all_videos():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
|
|
||||||
with ZipFile('zip_exports/all_videos.zip', 'w') as zipf: #no compression, need to add zipfile.ZIP_DEFLATED for compression
|
with ZipFile('zip_exports/all_videos.zip', 'w') as zipf: #no compression, need to add zipfile.ZIP_DEFLATED for compression
|
||||||
zipdir('uploads/', zipf)
|
zipdir('uploads/', zipf)
|
||||||
|
|
||||||
return send_file("zip_exports/all_videos.zip", as_attachment=False, download_name="all_tables.zip")
|
return send_file("zip_exports/all_videos.zip", as_attachment=False, download_name="all_videos.zip")
|
||||||
|
|
||||||
|
|
||||||
def create_csv(table, filename):
|
def create_csv(table, filename):
|
||||||
@@ -489,24 +577,13 @@ def export_csv(table_name):
|
|||||||
# the contents of all tables
|
# the contents of all tables
|
||||||
@app.route("/table_contents")
|
@app.route("/table_contents")
|
||||||
def table_contents():
|
def table_contents():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
meta = db.metadata
|
meta = db.metadata
|
||||||
#meta.reflect(db.engine) # Uncomment this to also get the hidden tables, but this crashes rn
|
#meta.reflect(db.engine) # Uncomment this to also get the hidden tables, but this crashes rn
|
||||||
tables = meta.tables.keys()
|
tables = meta.tables.keys()
|
||||||
table_contents = {}
|
table_contents = {}
|
||||||
|
|
||||||
#Testing querys for exporting etc
|
|
||||||
print("tables: ",tables)
|
|
||||||
print("testquerys:")
|
|
||||||
qtable = meta.tables["default_demographic_test"]
|
|
||||||
query1 = select(qtable).where(qtable.c.alter == 78)
|
|
||||||
print("Query 1: ", query1)
|
|
||||||
print("Query 1 result: ")
|
|
||||||
result = db.session.execute(query1)
|
|
||||||
print("Columns: ", result.columns)
|
|
||||||
for row in result:
|
|
||||||
print(row)
|
|
||||||
#Test End
|
|
||||||
|
|
||||||
for table_name in tables:
|
for table_name in tables:
|
||||||
table = meta.tables[table_name]
|
table = meta.tables[table_name]
|
||||||
columns = table.columns.keys()
|
columns = table.columns.keys()
|
||||||
@@ -532,33 +609,76 @@ def table_contents():
|
|||||||
|
|
||||||
@app.route('/show_tables')
|
@app.route('/show_tables')
|
||||||
def show_tables():
|
def show_tables():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
meta = db.metadata
|
meta = db.metadata
|
||||||
meta.reflect(db.engine)
|
meta.reflect(db.engine)
|
||||||
tables = meta.tables
|
tables = meta.tables
|
||||||
return render_template('show_tables.html', tables=tables)
|
return render_template('show_tables.html', tables=tables)
|
||||||
|
|
||||||
# Control Panel ---------------------------------------------------------
|
@app.route("/manage_uploads")
|
||||||
|
def manage_uploads():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
|
|
||||||
|
videodir = "uploads/"
|
||||||
|
videolist = os.listdir(videodir)
|
||||||
|
num_videos = len(videolist)
|
||||||
|
|
||||||
|
return render_template("manage_uploads.html", videolist=videolist, num_videos=num_videos)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/deleteuploads", methods=["POST"])
|
||||||
|
def deleteuploads():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
|
|
||||||
|
print("deleting all videos")
|
||||||
|
|
||||||
|
videodir = "uploads/"
|
||||||
|
for video in os.listdir(videodir):
|
||||||
|
os.remove(os.path.join(videodir, video))
|
||||||
|
|
||||||
|
print("videos deleted")
|
||||||
|
|
||||||
|
return redirect("/all_links")
|
||||||
|
|
||||||
|
@app.route("/task3")
|
||||||
|
def task3():
|
||||||
|
return render_template("task3.html")
|
||||||
|
|
||||||
@app.route("/upload_configs")
|
|
||||||
def upload_configs():
|
|
||||||
links = []
|
|
||||||
for rule in app.url_map.iter_rules():
|
|
||||||
# Filter out rules we can't navigate to in a browser
|
|
||||||
# and rules that require parameters
|
|
||||||
if "GET" in rule.methods and has_no_empty_params(rule):
|
|
||||||
url = url_for(rule.endpoint, **(rule.defaults or {}))
|
|
||||||
links.append((url, rule.endpoint))
|
|
||||||
return render_template("all_links.html", links=links)
|
|
||||||
|
|
||||||
|
|
||||||
# Root page -----------------------------
|
# Root page -----------------------------
|
||||||
|
|
||||||
|
@app.route("/login", methods=["GET","POST"])
|
||||||
|
def login():
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
pwhash = hashlib.sha256(request.form["password"].encode('utf-8')).hexdigest()
|
||||||
|
if pwhash == PASSWORD:
|
||||||
|
session["logged_in"] = True
|
||||||
|
return redirect(url_for("all_links"))
|
||||||
|
|
||||||
|
return render_template("login.html")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/logout")
|
||||||
|
def logout():
|
||||||
|
session["logged_in"] = False
|
||||||
|
return redirect("/")
|
||||||
|
|
||||||
def has_no_empty_params(rule):
|
def has_no_empty_params(rule):
|
||||||
defaults = rule.defaults if rule.defaults is not None else ()
|
defaults = rule.defaults if rule.defaults is not None else ()
|
||||||
arguments = rule.arguments if rule.arguments is not None else ()
|
arguments = rule.arguments if rule.arguments is not None else ()
|
||||||
return len(defaults) >= len(arguments)
|
return len(defaults) >= len(arguments)
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
|
def root():
|
||||||
|
return redirect("/start")
|
||||||
|
|
||||||
|
@app.route("/all_links")
|
||||||
def all_links():
|
def all_links():
|
||||||
links = []
|
links = []
|
||||||
for rule in app.url_map.iter_rules():
|
for rule in app.url_map.iter_rules():
|
||||||
@@ -572,7 +692,7 @@ def all_links():
|
|||||||
# delete all tables as last link --------------------------
|
# delete all tables as last link --------------------------
|
||||||
|
|
||||||
# Route to delete all entries
|
# Route to delete all entries
|
||||||
@app.route('/delete_json_tables', methods=['GET'])
|
#@app.route('/delete_json_tables', methods=['GET'])
|
||||||
def delete_json_tables():
|
def delete_json_tables():
|
||||||
try:
|
try:
|
||||||
meta = db.metadata
|
meta = db.metadata
|
||||||
@@ -596,6 +716,8 @@ def delete_json_tables():
|
|||||||
# Route to delete all entries
|
# Route to delete all entries
|
||||||
@app.route('/delete_all_entries', methods=['GET'])
|
@app.route('/delete_all_entries', methods=['GET'])
|
||||||
def delete_all_entries():
|
def delete_all_entries():
|
||||||
|
if not session.get("logged_in"):
|
||||||
|
return redirect("/login")
|
||||||
# here I could also use a "drop_all()", that works jsut like create all from the creation part
|
# here I could also use a "drop_all()", that works jsut like create all from the creation part
|
||||||
# this together with the reflect could drop actually all tables
|
# this together with the reflect could drop actually all tables
|
||||||
try:
|
try:
|
||||||
@@ -612,5 +734,8 @@ def delete_all_entries():
|
|||||||
# Close the session
|
# Close the session
|
||||||
db.session.close()
|
db.session.close()
|
||||||
|
|
||||||
|
def create_app():
|
||||||
|
return app
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run()
|
app.run()
|
||||||
@@ -1,55 +1,4 @@
|
|||||||
{
|
{
|
||||||
"Block 0":{
|
|
||||||
"type": "TaskTemplate",
|
|
||||||
"tempalte": "standard_template.html",
|
|
||||||
"stimuli":{
|
|
||||||
"type":"double_video",
|
|
||||||
"list_1":{
|
|
||||||
"video_1":"https://www.youtube-nocookie.com/embed/VtnwHmabyzo?si=H3rrG-GHtlSymR70",
|
|
||||||
"video_2":"https://www.youtube-nocookie.com/embed/EL76Ok4r0aQ?si=hqUm8eUUfX39NN4L",
|
|
||||||
"video_3":"https://www.youtube-nocookie.com/embed/XTMIomsXxKM?si=r2zB6OKERH6Jdpi6"
|
|
||||||
},
|
|
||||||
"list_2":{
|
|
||||||
"video_1":"https://www.youtube-nocookie.com/embed/VtnwHmabyzo?si=H3rrG-GHtlSymR70",
|
|
||||||
"video_2":"https://www.youtube-nocookie.com/embed/EL76Ok4r0aQ?si=hqUm8eUUfX39NN4L",
|
|
||||||
"video_3":"https://www.youtube-nocookie.com/embed/XTMIomsXxKM?si=r2zB6OKERH6Jdpi6"
|
|
||||||
},
|
|
||||||
"configuration":{
|
|
||||||
"embed":"yt"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"questions":{
|
|
||||||
"question1":{
|
|
||||||
"type": "likert",
|
|
||||||
"name": "likertscale",
|
|
||||||
"text": "How would you rate this video?",
|
|
||||||
"required": "true",
|
|
||||||
"points":{
|
|
||||||
"p1":{
|
|
||||||
"value":"1",
|
|
||||||
"text":"I dont like it at all"
|
|
||||||
},
|
|
||||||
"p2":{
|
|
||||||
"value":"2",
|
|
||||||
"text":"I am indifferent"
|
|
||||||
},
|
|
||||||
"p3":{
|
|
||||||
"value":"3",
|
|
||||||
"text":"I like it a lot"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"database_table" :{
|
|
||||||
"table_name": "double_video_responses",
|
|
||||||
"fields": {
|
|
||||||
"likertscale":{
|
|
||||||
"type": "integer",
|
|
||||||
"nullable": "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Block 1": {
|
"Block 1": {
|
||||||
"type": "TaskTemplate",
|
"type": "TaskTemplate",
|
||||||
"tempalte": "standard_template.html",
|
"tempalte": "standard_template.html",
|
||||||
@@ -153,6 +102,13 @@
|
|||||||
"max": "10"
|
"max": "10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"infovideo": {
|
||||||
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. \n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
"database_table": {
|
"database_table": {
|
||||||
"table_name": "demographic_data",
|
"table_name": "demographic_data",
|
||||||
"fields": {
|
"fields": {
|
||||||
@@ -193,9 +149,8 @@
|
|||||||
"type": "single_video",
|
"type": "single_video",
|
||||||
"order": "random",
|
"order": "random",
|
||||||
"list": {
|
"list": {
|
||||||
"video_1":"https://www.youtube-nocookie.com/embed/VtnwHmabyzo?si=H3rrG-GHtlSymR70",
|
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522",
|
||||||
"video_2":"https://www.youtube-nocookie.com/embed/EL76Ok4r0aQ?si=hqUm8eUUfX39NN4L",
|
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-"
|
||||||
"video_3":"https://www.youtube-nocookie.com/embed/XTMIomsXxKM?si=r2zB6OKERH6Jdpi6"
|
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"embed": "yt"
|
"embed": "yt"
|
||||||
@@ -205,45 +160,52 @@
|
|||||||
"question1": {
|
"question1": {
|
||||||
"type": "likert",
|
"type": "likert",
|
||||||
"name": "likertscale",
|
"name": "likertscale",
|
||||||
"text": "How would you rate this video?",
|
"text": "Wie würden sie dieses Video bewerten?",
|
||||||
"required": "true",
|
"required": "true",
|
||||||
"points": {
|
"points": {
|
||||||
"p1": {
|
"p1": {
|
||||||
"value": "1",
|
"value": "1",
|
||||||
"text":"I dont like it at all"
|
"text": "Ich finde es gar nicht gut 🙁👎"
|
||||||
},
|
},
|
||||||
"p2": {
|
"p2": {
|
||||||
"value": "2",
|
"value": "2",
|
||||||
"text":"I dont like it"
|
"text": "Ich finde es nicht gut 👎"
|
||||||
},
|
},
|
||||||
"p3": {
|
"p3": {
|
||||||
"value": "3",
|
"value": "3",
|
||||||
"text":"I am indifferent"
|
"text": "Ich finde es weder gut noch schlecht"
|
||||||
},
|
},
|
||||||
"p4": {
|
"p4": {
|
||||||
"value": "4",
|
"value": "4",
|
||||||
"text":"I like it"
|
"text": "Ich finde es gut 👍"
|
||||||
},
|
},
|
||||||
"p5": {
|
"p5": {
|
||||||
"value": "5",
|
"value": "5",
|
||||||
"text":"I like it a lot"
|
"text": "Ich finde es sehr gut 😊👍"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"question2": {
|
"question2": {
|
||||||
"type": "textinput",
|
"type": "textinput",
|
||||||
"name": "text_feedback",
|
"name": "text_feedback",
|
||||||
"text": "Here you can give us Feedback",
|
"text": "Hier können sie uns Feedback geben",
|
||||||
"required": "false",
|
"required": "false",
|
||||||
"size": "250"
|
"size": "250"
|
||||||
},
|
},
|
||||||
"question3": {
|
"question3": {
|
||||||
"type": "videoinput",
|
"type": "videoinput",
|
||||||
"text": "Here you can give us Feedback as video",
|
"text": "Hier können sie per Video Feedback geben",
|
||||||
"name": "video_feedback",
|
"name": "video_feedback",
|
||||||
"required": "false"
|
"required": "false"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"infovideo": {
|
||||||
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden.\\n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt.\\n Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
"database_table": {
|
"database_table": {
|
||||||
"table_name": "single_video_responses",
|
"table_name": "single_video_responses",
|
||||||
"fields": {
|
"fields": {
|
||||||
@@ -264,8 +226,96 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Block_3":{
|
"Block 3": {
|
||||||
"type": "SinglePage",
|
"type": "TaskTemplate",
|
||||||
"template": "endpage.html"
|
"tempalte": "standard_template.html",
|
||||||
|
"stimuli": {
|
||||||
|
"type": "double_video",
|
||||||
|
"list_1": {
|
||||||
|
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522",
|
||||||
|
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-"
|
||||||
|
},
|
||||||
|
"list_2": {
|
||||||
|
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-",
|
||||||
|
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"question1": {
|
||||||
|
"type": "likert",
|
||||||
|
"name": "likertscale",
|
||||||
|
"text": "Welches Video gefällt ihnen besser?",
|
||||||
|
"required": "true",
|
||||||
|
"points": {
|
||||||
|
"p1": {
|
||||||
|
"value": "1",
|
||||||
|
"text": "Ich finde das linke Video besser"
|
||||||
|
},
|
||||||
|
"p2": {
|
||||||
|
"value": "2",
|
||||||
|
"text": "Ich finde beide Videos gleich gut"
|
||||||
|
},
|
||||||
|
"p3": {
|
||||||
|
"value": "3",
|
||||||
|
"text": "Ich finde das rechte Video besser"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"infovideo": {
|
||||||
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database_table": {
|
||||||
|
"table_name": "double_video_responses",
|
||||||
|
"fields": {
|
||||||
|
"likertscale": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Block 4": {
|
||||||
|
"type": "TaskTemplate",
|
||||||
|
"tempalte": "standard_template.html",
|
||||||
|
"stimuli": {
|
||||||
|
"type": "empty",
|
||||||
|
"list": {
|
||||||
|
"empty_stimulus": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"question1": {
|
||||||
|
"type": "textinput",
|
||||||
|
"name": "formfeedback",
|
||||||
|
"text": "Das war der Prototyp für dieses Studientool. Über Feedback würde ich mich freuen. Entweder hier oder per Email unter: avatarstudy@proton.me",
|
||||||
|
"required": "false",
|
||||||
|
"size": "1000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"infovideo": {
|
||||||
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database_table": {
|
||||||
|
"table_name": "feedback_responses",
|
||||||
|
"fields": {
|
||||||
|
"formfeedback": {
|
||||||
|
"type": "string",
|
||||||
|
"size": "1000",
|
||||||
|
"nullable": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
slaeforms/dockerfile
Normal file
17
slaeforms/dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Use the official Python image from the Docker Hub
|
||||||
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
# Set the working directory
|
||||||
|
WORKDIR /slaeforms
|
||||||
|
|
||||||
|
# Copy the rest of the application code to the working directory
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Install the dependencies
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Expose the port on which the app will run
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Define the command to run the application using Gunicorn
|
||||||
|
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:create_app()"]
|
||||||
7
slaeforms/exports/demographic_data.csv
Normal file
7
slaeforms/exports/demographic_data.csv
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
id,user_id,date_created,stimulus_name,alter,geschlecht,bildung,hoerstatus,wann_gehörlos,wann_gebärdensprache,eltern_gehörlos,zuhause_sl,arbeit_sl,avatar_erfahrung
|
||||||
|
e0b08915-2975-42ad-8a7c-6c057d914120,1cbab591-9fe8-4e2b-adce-e40ef14ed49d,2024-09-19 15:16:25.413235,empty_stimulus,23,Männlich,Bachelor,Hörend,-1,23,keiner,zuhause-Deutsch,"arbeit-Deutsch,arbeit-Sonstige",Ja
|
||||||
|
6b1d95ed-646d-42dc-b386-d3aacc41d6ed,e8797746-73a1-4b0a-b644-c084d155b3d6,2024-09-19 16:21:20.372629,empty_stimulus,2,Männlich,Hauptschule,GehörlosCI,2,3,beide,"zuhause-Deutsch,zuhause-Gebärdensprache","arbeit-Deutsch,arbeit-Gebärdensprache,arbeit-Sonstige",Ja
|
||||||
|
0103472b-943b-4728-9b50-dc43a886facf,9eb6c08d-1eab-44c3-87a6-8a0a6848adc6,2024-09-21 11:40:35.811739,empty_stimulus,2,Männlich,Abitur,Schwerhörig,2,2,einer,zuhause-Deutsch,arbeit-Sonstige,Nein
|
||||||
|
88e4cb27-0d97-466d-a164-55b657d648ef,dd296f2b-a497-4957-899a-9393b25ab86f,2024-09-23 14:52:29.344441,empty_stimulus,2,Divers,Realschule,GehörlosCI,2,2,einer,"zuhause-Deutsch,zuhause-Gebärdensprache",arbeit-Deutsch,Ja
|
||||||
|
85e2cc7c-25ba-473b-a3d1-26fac4ca9629,6ece9745-96d7-40e1-a8b1-598608723f3a,2024-10-02 11:51:05.384542,empty_stimulus,67,Männlich,Master,Schwerhörig,66,66,keiner,"zuhause-Deutsch,zuhause-Gebärdensprache",arbeit-Deutsch,Nein
|
||||||
|
54f00de7-4351-47f1-a798-1c5326b3d8da,1e63ca71-bb2e-4d19-a69e-b7e8dccaba35,2024-10-02 11:56:41.492195,empty_stimulus,27,Männlich,Bachelor,Hörend,-1,23,keiner,zuhause-Deutsch,"arbeit-Deutsch,arbeit-Sonstige",Ja
|
||||||
|
5
slaeforms/exports/double_video_responses.csv
Normal file
5
slaeforms/exports/double_video_responses.csv
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
id,user_id,date_created,stimulus_name,likertscale
|
||||||
|
8240918c-aaf9-4dc8-b868-f4cec9920dfc,60c9c65b-b6b7-4510-8fb1-e9f220a7c46e,2024-06-27 17:43:33.469473,"('video_1', 'video_2')",2
|
||||||
|
36ef34e3-0e47-4980-86f9-e3456b4bf12c,60c9c65b-b6b7-4510-8fb1-e9f220a7c46e,2024-06-27 17:43:35.573252,"('video_2', 'video_1')",2
|
||||||
|
253a2bdd-3c33-47b6-a715-a2b167b11de3,253b881d-cc08-4835-bf03-4d0ffdd8eddd,2024-06-27 17:44:32.383837,"('video_1', 'video_2')",2
|
||||||
|
ce8f86ee-fe37-45db-9a7e-a8cba56cd1da,253b881d-cc08-4835-bf03-4d0ffdd8eddd,2024-06-27 17:44:35.019425,"('video_2', 'video_1')",2
|
||||||
|
5
slaeforms/exports/single_video_responses.csv
Normal file
5
slaeforms/exports/single_video_responses.csv
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
id,user_id,date_created,stimulus_name,likertscale,text_feedback,video_upload
|
||||||
|
9affead9-d952-47dd-be8f-f1f746f9426d,60c9c65b-b6b7-4510-8fb1-e9f220a7c46e,2024-06-27 17:43:51.471157,video_2,3,test,
|
||||||
|
e4c5df2c-0244-4ec6-bd2c-02eff4a4c5f1,60c9c65b-b6b7-4510-8fb1-e9f220a7c46e,2024-06-27 17:43:55.326471,video_1,3,,
|
||||||
|
12313ba8-1f3e-4ea4-a39e-42021a46d0a7,253b881d-cc08-4835-bf03-4d0ffdd8eddd,2024-06-27 17:44:47.661124,video_1,3,,
|
||||||
|
c5cc69d6-d51e-4836-aabd-54d3b0682511,253b881d-cc08-4835-bf03-4d0ffdd8eddd,2024-06-27 17:44:50.468067,video_2,3,,
|
||||||
|
@@ -1,2 +1,7 @@
|
|||||||
user_id,device_id,question_order,date_created
|
user_id,device_id,question_order,date_created,form_completed
|
||||||
662dc5a5-ff08-4270-ad33-444e8dd01514,50bc84f6-6c55-4277-9651-5c3c98e973f5,"{'Block 0': [('video_1', 'video_1'), ('video_2', 'video_2'), ('video_3', 'video_3')], 'Block 1': ['empty_stimulus'], 'Block 2': ['video_1', 'video_3', 'video_2']}",2024-06-25 12:01:22.516505
|
1cbab591-9fe8-4e2b-adce-e40ef14ed49d,71f05b18-36d1-45bc-8b7a-418d05a78c3b,"{'Block 1': ['empty_stimulus'], 'Block 2': ['video_7', 'video_15', 'video_5', 'video_9', 'video_3', 'video_8', 'video_11', 'video_6', 'video_4', 'video_12', 'video_1', 'video_14', 'video_10', 'video_13', 'video_2'], 'Block 3': [('video_1', 'video_1')], 'Block 4': ['video_1']}",2024-09-19 15:15:17.910737,True
|
||||||
|
e8797746-73a1-4b0a-b644-c084d155b3d6,71f05b18-36d1-45bc-8b7a-418d05a78c3b,"{'Block 1': ['empty_stimulus'], 'Block 2': ['video_10', 'video_11', 'video_14', 'video_5', 'video_1', 'video_2', 'video_12', 'video_7', 'video_3', 'video_13', 'video_8', 'video_6', 'video_4', 'video_15', 'video_9'], 'Block 3': [('video_1', 'video_1')], 'Block 4': ['video_1']}",2024-09-19 16:21:05.738180,False
|
||||||
|
9eb6c08d-1eab-44c3-87a6-8a0a6848adc6,ccc2054d-295e-47f5-b277-2282109c4ed1,"{'Block 1': ['empty_stimulus'], 'Block 2': ['video_9', 'video_2', 'video_4', 'video_6', 'video_13', 'video_14', 'video_15', 'video_11', 'video_10', 'video_7', 'video_5', 'video_8', 'video_12', 'video_1', 'video_3'], 'Block 3': [('video_1', 'video_1')], 'Block 4': ['video_1']}",2024-09-21 11:40:21.272823,False
|
||||||
|
dd296f2b-a497-4957-899a-9393b25ab86f,d94cc6b1-958c-43e4-9789-9e0c369ba29a,"{'Block 1': ['empty_stimulus'], 'Block 2': ['video_2', 'video_11', 'video_9', 'video_6', 'video_4', 'video_5', 'video_3', 'video_8', 'video_10', 'video_7', 'video_15', 'video_14', 'video_1', 'video_13', 'video_12'], 'Block 3': [('video_1', 'video_1')], 'Block 4': ['video_1']}",2024-09-23 14:52:02.034386,False
|
||||||
|
6ece9745-96d7-40e1-a8b1-598608723f3a,588e94df-870d-4c61-b3c8-098edf01e988,"{'Block 1': ['empty_stimulus'], 'Block 2': ['video_14', 'video_8', 'video_5', 'video_6', 'video_1', 'video_7', 'video_4', 'video_2', 'video_15', 'video_9', 'video_11', 'video_13', 'video_10', 'video_3', 'video_12'], 'Block 3': [('video_1', 'video_1')], 'Block 4': ['video_1'], 'Block 5': ['video_1']}",2024-10-02 11:49:11.652504,False
|
||||||
|
1e63ca71-bb2e-4d19-a69e-b7e8dccaba35,8a1063c3-7130-4ab9-9d88-bd6bf470e685,"{'Block 1': ['empty_stimulus'], 'Block 2': ['video_13', 'video_2', 'video_12', 'video_8', 'video_3', 'video_7', 'video_14', 'video_1', 'video_11', 'video_9', 'video_15', 'video_6', 'video_4', 'video_5', 'video_10'], 'Block 3': [('video_1', 'video_1')], 'Block 4': ['video_1'], 'Block 5': ['video_1']}",2024-10-02 11:55:43.185190,True
|
||||||
|
|||||||
|
16
slaeforms/requirements.txt
Normal file
16
slaeforms/requirements.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
blinker==1.8.2
|
||||||
|
click==8.1.7
|
||||||
|
colorama==0.4.6
|
||||||
|
Flask==3.0.3
|
||||||
|
Flask-SQLAlchemy==3.1.1
|
||||||
|
Flask-WTF==1.2.1
|
||||||
|
greenlet==3.0.3
|
||||||
|
gunicorn==22.0.0
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
Jinja2==3.1.4
|
||||||
|
MarkupSafe==2.1.5
|
||||||
|
packaging==24.1
|
||||||
|
SQLAlchemy==2.0.30
|
||||||
|
typing_extensions==4.12.2
|
||||||
|
Werkzeug==3.0.3
|
||||||
|
WTForms==3.1.2
|
||||||
BIN
slaeforms/static/icons/sl-icon.png
Normal file
BIN
slaeforms/static/icons/sl-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
13
slaeforms/static/infoDialogScript.js
Normal file
13
slaeforms/static/infoDialogScript.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const dialog = document.querySelector("dialog");
|
||||||
|
const showButton = document.querySelector("dialog + button");
|
||||||
|
const closeButton = document.querySelector("dialog button");
|
||||||
|
|
||||||
|
// "Show the dialog" button opens the dialog modally
|
||||||
|
showButton.addEventListener("click", () => {
|
||||||
|
dialog.showModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
// "Close" button closes the dialog
|
||||||
|
closeButton.addEventListener("click", () => {
|
||||||
|
dialog.close();
|
||||||
|
});
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: #a4b5ff;
|
background-color: #a4b5ff;
|
||||||
@@ -40,8 +38,9 @@ dialog .iframe-container{
|
|||||||
height: 90px;
|
height: 90px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 30px;
|
||||||
left: 80vw;
|
left: min(calc(66vw + 30px + 34vw / 2), calc(1720px + calc(100vw - 1690px) / 2));
|
||||||
|
/*first is the normal case, second if 66vw is more than 1690 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.infoButtonIcon {
|
.infoButtonIcon {
|
||||||
@@ -50,22 +49,52 @@ dialog .iframe-container{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
width: 300px;
|
||||||
|
background: #6cd1e1;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
align-content: center;
|
||||||
|
margin-top: 40vh;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: 50vh;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-elements {
|
||||||
|
display: inline-block;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
#loginbutton {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 12px 24px;
|
||||||
|
/* Increased padding for a bigger button */
|
||||||
|
font-size: 25px;
|
||||||
|
/* Increased font size */
|
||||||
|
border: none;
|
||||||
|
/* Removes default border */
|
||||||
|
border-radius: 8px;
|
||||||
|
/* Optional: rounds the corners of the button */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
/* height: 100vh;*/
|
/* height: 100vh;*/
|
||||||
width: 60vw; /* You can adjust this width as needed */
|
width: 66vw;
|
||||||
max-width: 1200px; /* Maximum width to keep it from getting too wide on large screens */
|
/* You can adjust this width as needed */
|
||||||
|
max-width: 1690px;
|
||||||
|
/* Maximum width to keep it from getting too wide on large screens */
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #7b8cdb; /* Just for visual differentiation */
|
background-color: #b6c3ff; /* used to be 7b8cdb */
|
||||||
|
/* Just for visual differentiation */
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.textblock {
|
.textblock {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
display: flex;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@@ -77,6 +106,10 @@ form {
|
|||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.questioncontainer {
|
||||||
|
max-width: 70%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.dsgvoform {
|
.dsgvoform {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
@@ -89,9 +122,7 @@ label {
|
|||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
input,
|
.inputs {
|
||||||
textarea,
|
|
||||||
select {
|
|
||||||
margin: 10px 0 0 0;
|
margin: 10px 0 0 0;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
@@ -101,15 +132,21 @@ select {
|
|||||||
.button-container input {
|
.button-container input {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 30px; /* Adjust as needed for spacing */
|
margin-top: 30px;
|
||||||
|
/* Adjust as needed for spacing */
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container {
|
.button-container {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
/* buttons */
|
/* buttons */
|
||||||
.buttondisable {
|
.buttondisable {
|
||||||
filter: invert(65%);
|
filter: invert(65%);
|
||||||
@@ -117,14 +154,22 @@ select {
|
|||||||
|
|
||||||
#submitbutton {
|
#submitbutton {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 12px 24px; /* Increased padding for a bigger button */
|
padding: 12px 24px;
|
||||||
font-size: 25px; /* Increased font size */
|
/* Increased padding for a bigger button */
|
||||||
border: none; /* Removes default border */
|
font-size: 25px;
|
||||||
border-radius: 8px; /* Optional: rounds the corners of the button */
|
/* Increased font size */
|
||||||
|
border: none;
|
||||||
|
/* Removes default border */
|
||||||
|
border-radius: 8px;
|
||||||
|
/* Optional: rounds the corners of the button */
|
||||||
width: auto;
|
width: auto;
|
||||||
|
float: right;
|
||||||
|
border: 1px solid #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#submitbutton:hover {
|
#submitbutton:hover {
|
||||||
background-color: #0056b3; /* Darker shade for hover effect */
|
background-color: #0056b3;
|
||||||
|
/* Darker shade for hover effect */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -132,13 +177,17 @@ select {
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textarea-container textarea {
|
.textarea-container textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 1.5rem auto;
|
margin: 1.5rem auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textarea-label {
|
.textarea-label {
|
||||||
align-self: flex-start; /* Aligns the label to the start of the container */
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper */
|
/* Helper */
|
||||||
@@ -151,7 +200,7 @@ select {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2,h3 {
|
h2 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,19 +219,24 @@ h2,h3 {
|
|||||||
|
|
||||||
/* Video recording controls */
|
/* Video recording controls */
|
||||||
.videocontrols {
|
.videocontrols {
|
||||||
width: 100px; /* Set a specific width for the buttons */
|
width: 100px;
|
||||||
height: 70px; /* Set a specific height for the buttons */
|
/* Set a specific width for the buttons */
|
||||||
|
height: 70px;
|
||||||
|
/* Set a specific height for the buttons */
|
||||||
background-color: #cae4ff;
|
background-color: #cae4ff;
|
||||||
border: none;
|
border: 1px solid #000;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.3s ease;
|
||||||
display: inline-flex; /* Display button contents as a flexbox */
|
display: inline-flex;
|
||||||
justify-content: center; /* Center contents horizontally */
|
/* Display button contents as a flexbox */
|
||||||
align-items: center; /* Center contents vertically */
|
justify-content: center;
|
||||||
|
/* Center contents horizontally */
|
||||||
|
align-items: center;
|
||||||
|
/* Center contents vertically */
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,9 +245,12 @@ h2,h3 {
|
|||||||
max-height: 65%;
|
max-height: 65%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
width: auto; /* Make the image fill its container */
|
width: auto;
|
||||||
height: auto; /* Make the image fill its container */
|
/* Make the image fill its container */
|
||||||
display: block; /* Remove any extra space around the image */
|
height: auto;
|
||||||
|
/* Make the image fill its container */
|
||||||
|
display: block;
|
||||||
|
/* Remove any extra space around the image */
|
||||||
}
|
}
|
||||||
|
|
||||||
.columncontainer {
|
.columncontainer {
|
||||||
@@ -204,20 +261,24 @@ h2,h3 {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
border: 3px solid black;
|
border: 3px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.columnright {
|
.columnright {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 3px solid black;
|
border: 3px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Video recording video and youtube iframe */
|
/* Video recording video and youtube iframe */
|
||||||
video { /* Video should not be bigger than 100% */
|
video {
|
||||||
|
/* Video should not be bigger than 100% */
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
margin: auto auto;
|
margin: auto auto;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe { /* center the iframe, mostly unnecessary */
|
iframe {
|
||||||
|
/* center the iframe, mostly unnecessary */
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,14 +292,33 @@ iframe { /* center the iframe, mostly unnecessary */
|
|||||||
|
|
||||||
.iframe-container {
|
.iframe-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 56.25%; /* 16:9 */
|
/*padding-bottom: 56.25%;*/
|
||||||
|
/* 16:9 */
|
||||||
|
padding-bottom: 100%;
|
||||||
|
/* 1:1 */
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iframe-container2 {
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 56.25%;
|
||||||
|
/* 16:9 */
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iframe-container2 iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.video-container {
|
.video-container {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 56.25%; /* 16:9 */
|
padding-bottom: 56.25%;
|
||||||
|
/* 16:9 */
|
||||||
height: 0;
|
height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -259,16 +339,46 @@ iframe { /* center the iframe, mostly unnecessary */
|
|||||||
margin: auto 10px;
|
margin: auto 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dv_half {
|
.dv_half {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 45%;
|
width: 48%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.double_video_container {
|
.double_video_container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Likert stuff 2 */
|
||||||
|
|
||||||
|
.outer-likert-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.normal-likert-container { /* inner container */
|
||||||
|
display: flex;
|
||||||
|
gap: 10px; /* Adjust spacing */
|
||||||
|
text-align: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
max-width: 70%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.likertlabel {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.likertinput {
|
||||||
|
margin: auto;
|
||||||
|
width: 60%;
|
||||||
|
min-height: 2em;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
/* Likert stuff */
|
/* Likert stuff */
|
||||||
.likert {
|
.likert {
|
||||||
/* --likert-rows: 5;*/
|
/* --likert-rows: 5;*/
|
||||||
@@ -292,10 +402,11 @@ iframe { /* center the iframe, mostly unnecessary */
|
|||||||
aspect-ratio: 1.5 / 1;
|
aspect-ratio: 1.5 / 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.likercontainer{
|
.likertcontainer {
|
||||||
margin: 30px auto;
|
margin: 30px auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.likert span {
|
.likert span {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -316,7 +427,8 @@ iframe { /* center the iframe, mostly unnecessary */
|
|||||||
}
|
}
|
||||||
|
|
||||||
.likert input:focus+span {
|
.likert input:focus+span {
|
||||||
outline: auto 1px; /*-webkit-focus-ring-color*/
|
outline: auto 1px;
|
||||||
|
/*-webkit-focus-ring-color*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.likert span:hover {
|
.likert span:hover {
|
||||||
@@ -336,15 +448,19 @@ iframe { /* center the iframe, mostly unnecessary */
|
|||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
table-layout: auto; /* Allows columns to adjust to their content */
|
table-layout: auto;
|
||||||
width: auto; /* Adjusts the table width to the content */
|
/* Allows columns to adjust to their content */
|
||||||
|
width: auto;
|
||||||
|
/* Adjusts the table width to the content */
|
||||||
}
|
}
|
||||||
|
|
||||||
th, td {
|
th,
|
||||||
|
td {
|
||||||
border: 1px solid #dddddd;
|
border: 1px solid #dddddd;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
word-wrap: break-word; /* Ensures content wraps and doesn't overflow */
|
word-wrap: break-word;
|
||||||
|
/* Ensures content wraps and doesn't overflow */
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
|
|||||||
BIN
slaeforms/static/videos/0009-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0009-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0009-intro-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0009-intro-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0009-mocap.mp4
Normal file
BIN
slaeforms/static/videos/0009-mocap.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0009-simple.mp4
Normal file
BIN
slaeforms/static/videos/0009-simple.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0009-variation-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0009-variation-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0018-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0018-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0018-mocap.mp4
Normal file
BIN
slaeforms/static/videos/0018-mocap.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0018-simple.mp4
Normal file
BIN
slaeforms/static/videos/0018-simple.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0020-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0020-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0020-mocap.mp4
Normal file
BIN
slaeforms/static/videos/0020-mocap.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0020-simple.mp4
Normal file
BIN
slaeforms/static/videos/0020-simple.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0021-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0021-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0021-mocap.mp4
Normal file
BIN
slaeforms/static/videos/0021-mocap.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0021-simple.mp4
Normal file
BIN
slaeforms/static/videos/0021-simple.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0022-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0022-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0022-mocap.mp4
Normal file
BIN
slaeforms/static/videos/0022-mocap.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0022-simple.mp4
Normal file
BIN
slaeforms/static/videos/0022-simple.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0044-inflected.mp4
Normal file
BIN
slaeforms/static/videos/0044-inflected.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0044-mocap.mp4
Normal file
BIN
slaeforms/static/videos/0044-mocap.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/0044-simple.mp4
Normal file
BIN
slaeforms/static/videos/0044-simple.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/GLEISvariations.mp4
Normal file
BIN
slaeforms/static/videos/GLEISvariations.mp4
Normal file
Binary file not shown.
BIN
slaeforms/static/videos/platzhalter-video.mp4
Normal file
BIN
slaeforms/static/videos/platzhalter-video.mp4
Normal file
Binary file not shown.
@@ -1,64 +1,77 @@
|
|||||||
const buttonCamera = document.getElementById('buttonCamera');
|
const buttonCamera = document.getElementById('buttonCamera');
|
||||||
const buttonRecord = document.getElementById('buttonRecord');
|
const buttonRecord = document.getElementById('buttonRecord');
|
||||||
const buttonDelete = document.getElementById('buttonDelete');
|
const buttonDelete = document.getElementById('buttonDelete');
|
||||||
const videoDisplay = document.getElementById('videoDisplay');
|
|
||||||
const buttonCameraIcon = document.getElementById('buttonCameraIcon');
|
const buttonCameraIcon = document.getElementById('buttonCameraIcon');
|
||||||
const buttonRecordIcon = document.getElementById('buttonRecordIcon');
|
const buttonRecordIcon = document.getElementById('buttonRecordIcon');
|
||||||
const buttonDeleteIcon = document.getElementById('buttonDeleteIcon');
|
const buttonDeleteIcon = document.getElementById('buttonDeleteIcon');
|
||||||
const videoContainer = document.getElementById('videoContainer');
|
const countdownText = document.getElementById('countdown')
|
||||||
const videoContainerCss = document.querySelector(".video-container ") //might be unnecessary
|
|
||||||
var mediaRecorder = null;
|
const videoDisplay = document.getElementById('videoDisplay');
|
||||||
var stream = null;
|
const videoContainer = document.getElementById('videoContainer'); // div that contains the videodisplay
|
||||||
let recordedVideoBlob = null;
|
|
||||||
let isRecording = false;
|
var mediaRecorder = null; // interface of the Media Stream Recording API to record the video stream
|
||||||
let videoAccess = false;
|
var stream = null; // webcam video input stream
|
||||||
let videoHeigt = 720;
|
let recordedVideoBlob = null; // recorded videodata
|
||||||
|
let isRecording = false; // false to display record button, true to display stop button
|
||||||
|
let videoAccess = false; // true if user has given permission to use the webcam
|
||||||
|
|
||||||
|
let videotime = 70; // how many seconds video is allowed to be recorded
|
||||||
|
let timeleft = videotime; // counter for how much time is still left
|
||||||
|
var countdownTimer; //the timer object that will end the recording if it takes too long
|
||||||
|
|
||||||
|
// default video dimensions
|
||||||
|
let videoHeight = 720;
|
||||||
let videoWidth = 1280;
|
let videoWidth = 1280;
|
||||||
|
|
||||||
// Handle form submission
|
|
||||||
|
// handle form submission
|
||||||
|
//the Video is beeing send together with the form data
|
||||||
document.getElementById("question_form").addEventListener("submit", function (event) {
|
document.getElementById("question_form").addEventListener("submit", function (event) {
|
||||||
event.preventDefault(); // Prevent the default form submission
|
event.preventDefault(); // Prevent the default form submission
|
||||||
console.log("submit button pressed");
|
console.log("submit button pressed");
|
||||||
// Create a FormData object
|
// create a FormData object
|
||||||
const formData = new FormData(event.target);
|
const formData = new FormData(event.target);
|
||||||
|
|
||||||
console.log("form data: ",formData);
|
console.log("form data: ",formData);
|
||||||
|
|
||||||
// Append the recorded video Blob to the FormData object
|
// append the recorded video blob to the FormData object
|
||||||
if (recordedVideoBlob) {
|
if (recordedVideoBlob) {
|
||||||
console.log("video is available: ", recordedVideoBlob);
|
console.log("video is available: ", recordedVideoBlob);
|
||||||
formData.append("recordedVideo", recordedVideoBlob, "recordedVideo.webm");
|
formData.append("recordedVideo", recordedVideoBlob, "recordedVideo.webm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
console.log("Data to be submitted: ",formData);
|
console.log("Data to be submitted: ",formData);
|
||||||
|
|
||||||
// Use fetch to send the form data and video to the backend
|
|
||||||
console.log("try to send the form and video");
|
console.log("try to send the form and video");
|
||||||
|
|
||||||
|
// send the form data and video to the backend
|
||||||
fetch("/send", {
|
fetch("/send", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: formData
|
body: formData
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
|
// code to handle proper redirection after submit
|
||||||
console.log('Response:', response);
|
console.log('Response:', response);
|
||||||
// Check if response is a redirect (HTTP 3xx status)
|
// check if response is a redirect
|
||||||
if (response.redirected) {
|
if (response.redirected) {
|
||||||
console.log("Redirecting to:", response.url);
|
console.log("Redirecting to:", response.url);
|
||||||
window.location.href = response.url; // Redirect to the new page
|
window.location.href = response.url; // Redirect to the new page
|
||||||
} else {
|
} else {
|
||||||
console.log("Non-redirect response received.");
|
console.log("No redirect response received.");
|
||||||
// Handle other responses if needed
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
// Handle errors if fetch fails
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// enable/disable video recording feature
|
||||||
async function cameraButton() {
|
async function cameraButton() {
|
||||||
if (!videoAccess) {
|
if (!videoAccess) {
|
||||||
console.log("cameraButton case videoAccess = false");
|
console.log("cameraButton case videoAccess = false");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// ask the user for permission to use the webcam
|
||||||
|
// if given, assign it to "stream"
|
||||||
stream = await navigator.mediaDevices.getUserMedia({
|
stream = await navigator.mediaDevices.getUserMedia({
|
||||||
video: true,
|
video: true,
|
||||||
});
|
});
|
||||||
@@ -67,39 +80,62 @@ async function cameraButton() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("stream is active");
|
console.log("stream is active");
|
||||||
|
|
||||||
videoAccess = true;
|
videoAccess = true;
|
||||||
|
|
||||||
videoHeigt = stream.getVideoTracks()[0].getSettings().height
|
// set the dimensions of the webcam stream to the video display
|
||||||
|
videoHeight = stream.getVideoTracks()[0].getSettings().height
|
||||||
videoWidth = stream.getVideoTracks()[0].getSettings().width
|
videoWidth = stream.getVideoTracks()[0].getSettings().width
|
||||||
|
|
||||||
let aspectratio = (videoHeigt / videoWidth) *100
|
// calculate the aspec ratio
|
||||||
console.log("videoHeigt: ",videoHeigt);
|
let aspectratio = (videoHeight / videoWidth) *100;
|
||||||
console.log("videoWidth: ",videoWidth);
|
//console.log("videoHeight: ",videoHeight);
|
||||||
console.log("aspect ratio: ",aspectratio);
|
//console.log("videoWidth: ",videoWidth);
|
||||||
console.log("device: ",stream.getVideoTracks()[0].getSettings().deviceId);
|
//console.log("aspect ratio: ",aspectratio);
|
||||||
videoContainer.style.setProperty("padding-bottom", "min("+videoHeigt+"px,"+aspectratio+"%)");
|
//console.log("device: ",stream.getVideoTracks()[0].getSettings().deviceId);
|
||||||
|
|
||||||
if (videoHeigt > videoWidth){ //hochkant video
|
// adjust CSS to make the video fit properly
|
||||||
videoContainer.style.setProperty("max-width", "min(80%,576");
|
// this makes sure that there is no buggy "jumping" when the video display source changes
|
||||||
}else{ //Normal, horizontal
|
videoContainer.style.setProperty("padding-bottom", "min("+videoHeight+"px,"+aspectratio+"%), 100vh");
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: Solution for this part:
|
||||||
|
// If the video is vertical, I need to set the width to 0, the max-height to 100% and do the padding on the width, so turn the code around
|
||||||
|
//This should always make the video fitt
|
||||||
|
|
||||||
|
// adjust the max width for horizontal and vertical video input
|
||||||
|
if (videoHeight > videoWidth){ //hochkant video
|
||||||
|
// I did this originally to display vertical video on a horizontal screen properly (video should not be higher than the screem)
|
||||||
|
// but now I do this by adjusting the paddint to be at most 100vh, so this whole part should be useless now
|
||||||
|
// But a new problem could be if I do too little padding and the ratio is lost because of it, so actually I also need to adjust the width
|
||||||
|
videoContainer.style.setProperty("max-width", "min(80%,576)"); // maybe actually use the screen height here: instead of 80% maybe 80vh
|
||||||
|
}else{ //normal, horizontal
|
||||||
videoContainer.style.setProperty("max-width", "100%");
|
videoContainer.style.setProperty("max-width", "100%");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// show the webcam input stream on the video display
|
||||||
videoDisplay.srcObject = stream;
|
videoDisplay.srcObject = stream;
|
||||||
|
|
||||||
|
// change the icon to indicate the disable option
|
||||||
buttonCameraIcon.src = ICON_PATHS.cameraofficon;
|
buttonCameraIcon.src = ICON_PATHS.cameraofficon;
|
||||||
buttonCameraIcon.alt = "Camera-off Icon";
|
buttonCameraIcon.alt = "Camera-off Icon";
|
||||||
|
|
||||||
|
// display the elements for the video recording
|
||||||
buttonRecord.style.display = 'inline-block';
|
buttonRecord.style.display = 'inline-block';
|
||||||
buttonDelete.style.display = 'inline-block';
|
buttonDelete.style.display = 'inline-block';
|
||||||
videoDisplay.style.display = 'block';
|
videoDisplay.style.display = 'block';
|
||||||
videoContainer.style.display = 'block';
|
videoContainer.style.display = 'block';
|
||||||
videoDisplay.classList.add("videomirror");
|
videoDisplay.classList.add("videomirror");
|
||||||
|
|
||||||
|
// initialize MediaRecorder, give it the webcam stream as input to record
|
||||||
mediaRecorder = new MediaRecorder(stream, {
|
mediaRecorder = new MediaRecorder(stream, {
|
||||||
mimeType: "video/webm", // could use different video format
|
mimeType: "video/webm",
|
||||||
// videoBitsPerSecond: 5000000, // Standard bitrate for video is 2,5 mbps
|
audioBitsPerSecond: 0,
|
||||||
|
videoBitsPerSecond: 1900000, // Standard bitrate for video is 2,5 mbps
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// when data is available at the mediaRecorder (this means the recording has ended, since I have not specified time intervalls)
|
||||||
|
// save the data in "recordedVideoBlob"
|
||||||
mediaRecorder.addEventListener("dataavailable", (event) => {
|
mediaRecorder.addEventListener("dataavailable", (event) => {
|
||||||
console.log("Data available Event triggered");
|
console.log("Data available Event triggered");
|
||||||
if (event.data.size > 0) {
|
if (event.data.size > 0) {
|
||||||
@@ -110,28 +146,37 @@ async function cameraButton() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// when recording is stopped, display the recorded video
|
||||||
|
// TODO possibly replace this and just add it to the dataavailable event
|
||||||
|
// TODO this would ensure proper order in a concurrent scenario (the stop code here can only be executed after the dataavailable code happened)
|
||||||
|
// TODO part of it could also go to the record button function
|
||||||
mediaRecorder.addEventListener("stop", () => {
|
mediaRecorder.addEventListener("stop", () => {
|
||||||
if (recordedVideoBlob) {
|
if (recordedVideoBlob) {
|
||||||
videoDisplay.srcObject = null;
|
videoDisplay.srcObject = null; //remove the stream as input
|
||||||
videoDisplay.src = URL.createObjectURL(recordedVideoBlob);
|
videoDisplay.src = URL.createObjectURL(recordedVideoBlob); // create a url for the recorded video and set it as input
|
||||||
videoDisplay.controls = true;
|
videoDisplay.controls = true; // display video controls
|
||||||
videoDisplay.pause();
|
videoDisplay.pause(); // pause, so that it doesn't immediately play, TODO maybe disable autoplay?
|
||||||
|
|
||||||
buttonRecordIcon.src = ICON_PATHS.recordicon;
|
// TODO maybe move this to the record button function
|
||||||
|
buttonRecordIcon.src = ICON_PATHS.recordicon; //change the icon of the record button back
|
||||||
buttonRecordIcon.alt = 'Record Icon';
|
buttonRecordIcon.alt = 'Record Icon';
|
||||||
isRecording = false;
|
isRecording = false;
|
||||||
|
|
||||||
console.log('Recording stopped');
|
console.log('Recording stopped');
|
||||||
console.log("Src path:", videoDisplay.src);
|
console.log("Src path:", videoDisplay.src);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// -> the user disabled the videorecording feature
|
||||||
|
|
||||||
console.log("cameraButton case videoAccess = true");
|
console.log("cameraButton case videoAccess = true");
|
||||||
|
|
||||||
stream.getTracks().forEach(track => track.stop()); // Stop all tracks to release the camera
|
stream.getTracks().forEach(track => track.stop()); // stop all tracks to release the camera
|
||||||
stream = null;
|
stream = null;
|
||||||
videoAccess = false;
|
videoAccess = false;
|
||||||
|
|
||||||
|
// change the icon and hide all the elements again
|
||||||
buttonCameraIcon.src = ICON_PATHS.cameraicon;
|
buttonCameraIcon.src = ICON_PATHS.cameraicon;
|
||||||
buttonCameraIcon.alt = "Camera Icon";
|
buttonCameraIcon.alt = "Camera Icon";
|
||||||
buttonRecord.style.display = 'none';
|
buttonRecord.style.display = 'none';
|
||||||
@@ -142,41 +187,99 @@ async function cameraButton() {
|
|||||||
console.log("camera button function ends");
|
console.log("camera button function ends");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function recordButton() {
|
function recordButton() {
|
||||||
console.log("recordButton pressed");
|
console.log("recordButton pressed");
|
||||||
if (!isRecording) {
|
if (!isRecording) {
|
||||||
|
// a new recording starts
|
||||||
|
|
||||||
console.log("recordButton pressed case isRecording = false");
|
console.log("recordButton pressed case isRecording = false");
|
||||||
deleteButton();
|
|
||||||
videoDisplay.classList.add("videomirror");
|
deleteButton(); //delete previous video
|
||||||
buttonDelete.setAttribute("disabled", "");
|
|
||||||
buttonDeleteIcon.classList.add("buttondisable");
|
videoDisplay.classList.add("videomirror"); // mirror the video while recording, for a more natural experience
|
||||||
videoDisplay.srcObject = stream;
|
buttonDelete.setAttribute("disabled", ""); // can't delete during recording
|
||||||
videoDisplay.src = null;
|
buttonDeleteIcon.classList.add("buttondisable"); // delete button icon indicates that it is disabled
|
||||||
videoDisplay.controls = false;
|
|
||||||
mediaRecorder.start();
|
videoDisplay.src = null; // get rid of the previous video on the display
|
||||||
|
videoDisplay.srcObject = stream; // set webcam stream as input for the video display
|
||||||
|
videoDisplay.controls = false; // hide the video controls durin recording, because they are confusing
|
||||||
|
mediaRecorder.start(); // start recording
|
||||||
|
timeleft = videotime;
|
||||||
|
countdownTimer = setInterval(countdown, 1000) //stop the recording after "videotime" Seconds
|
||||||
|
|
||||||
|
|
||||||
console.log("video bitrate = ",mediaRecorder.videoBitsPerSecond);
|
console.log("video bitrate = ",mediaRecorder.videoBitsPerSecond);
|
||||||
|
|
||||||
|
// change icon to indicate "stop"
|
||||||
buttonRecordIcon.src = ICON_PATHS.stopicon;
|
buttonRecordIcon.src = ICON_PATHS.stopicon;
|
||||||
buttonRecordIcon.alt = 'Stop Icon';
|
buttonRecordIcon.alt = 'Stop Icon';
|
||||||
isRecording = true;
|
isRecording = true;
|
||||||
|
|
||||||
console.log('Recording started');
|
console.log('Recording started');
|
||||||
} else {
|
} else {
|
||||||
console.log("recordButton pressed case isRecording = true");
|
// recording got stopped
|
||||||
mediaRecorder.stop();
|
|
||||||
videoDisplay.classList.remove("videomirror");
|
|
||||||
|
|
||||||
|
console.log("recordButton pressed case isRecording = true");
|
||||||
|
|
||||||
|
clearInterval(countdownTimer)
|
||||||
|
|
||||||
|
stopRecording()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopRecording() {
|
||||||
|
mediaRecorder.stop(); // stop recording
|
||||||
|
videoDisplay.classList.remove("videomirror"); // don't mirror the videodisplay anymore
|
||||||
|
clearInterval(countdownTimer);
|
||||||
console.log("recording stops");
|
console.log("recording stops");
|
||||||
|
|
||||||
|
// enable the deletebutton again
|
||||||
buttonDelete.removeAttribute("disabled");
|
buttonDelete.removeAttribute("disabled");
|
||||||
buttonDeleteIcon.classList.remove("buttondisable");
|
buttonDeleteIcon.classList.remove("buttondisable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function timerStop() {
|
||||||
|
// recording got stopped by timer
|
||||||
|
|
||||||
|
console.log("timer stopped the recording");
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
stopRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
function countdown() {
|
||||||
|
if(timeleft <= 0){
|
||||||
|
countdownText.textContent = "";
|
||||||
|
timerStop();
|
||||||
|
clearInterval(countdownTimer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(timeleft >= 60){
|
||||||
|
r = timeleft - 60;
|
||||||
|
if(r< 10){
|
||||||
|
countdownText.textContent = "01:0"+r;
|
||||||
|
}else{
|
||||||
|
countdownText.textContent = "01:"+r;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(timeleft< 10){
|
||||||
|
countdownText.textContent = "00:0"+timeleft;
|
||||||
|
}else{
|
||||||
|
countdownText.textContent = "00:"+timeleft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeleft -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteButton() {
|
function deleteButton() {
|
||||||
// TODO delete data
|
// delete the recorded video
|
||||||
videoDisplay.controls = false;
|
videoDisplay.controls = false;
|
||||||
videoDisplay.srcObject = stream;
|
videoDisplay.srcObject = stream; // set webcam stream as source for the video display again
|
||||||
recordedVideoBlob = null
|
recordedVideoBlob = null
|
||||||
videoDisplay.classList.add("videomirror");
|
videoDisplay.classList.add("videomirror"); // mirror the video display during live feed again
|
||||||
|
|
||||||
|
// disable the deletebutton again
|
||||||
buttonDelete.setAttribute("disabled", "");
|
buttonDelete.setAttribute("disabled", "");
|
||||||
buttonDeleteIcon.classList.add("buttondisable");
|
buttonDeleteIcon.classList.add("buttondisable");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
<title>all links
|
<title>all links
|
||||||
</title>
|
</title>
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
<link rel="shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
153
slaeforms/templates/datenschutz.html
Normal file
153
slaeforms/templates/datenschutz.html
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study - Datenschutzerklärung</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h2>Datenschutzerklärung</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
<h3>
|
||||||
|
Information betroffener Personen zur Verarbeitung personenbezogener Daten
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Das DFKI (Deutsches Forschungszentrum für Künstliche Intelligenz) und seine Mitarbeiter/-innen setzen
|
||||||
|
sich ziel- und risikoorientiert für die informationelle Selbstbestimmung und das Grundrecht auf Schutz
|
||||||
|
personenbezogener Daten ein. In dieser Datenschutzerklärung informieren wir über die Verarbeitung
|
||||||
|
personenbezogener Daten in der gegebenen Studie.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Verantwortlicher
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Organisation: Deutsches Forschungszentrum für Künstliche Intelligenz, 66123 Saarbrücken
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Ansprechpartner: Patrick Gebhard, patrick.gebhard@dfki.de
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Datenschutzbeauftragter
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
DFKI-Datenschutzbeauftragter: Roland Vogt, roland.vogt@dfki.de
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Art der erhobenen Daten
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Im Rahmen der Studie werden personenbezogene Daten erhoben, namentlich Alter, Geschlecht, Bildungsgrad,
|
||||||
|
Hörstatus, seit wann der/die Teilnehmer*in Gehörlos ist, wie lange er/sie Gebärdensprache spricht, ob
|
||||||
|
die Eltern Gehörlos waren und welche Sprachen er/sie zuhause und auf der Arbeit/Schule verwendet.
|
||||||
|
Optional können Teilnehmer auch eigenständig Videoaufnahmen aufnehmen und hochladen.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Zweck der Verarbeitung
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
In der Studie bewerten Teilnehmer Videos von Gebärdensprachavataren und können freiwillig Feedback in
|
||||||
|
Form von Text oder Videoaufnahmen geben. Diese Daten werden soweit möglich vollständig anonymisiert
|
||||||
|
gespeichert. Aufgrund der Charakteristik der Videoaufnahmen ist eine vollständige Anonymisierung im
|
||||||
|
Auswertungsprozess nicht möglich. Die persönliche Zuordnung der betroffenen Personen ist jedoch zu jedem
|
||||||
|
Zeitpunkt für die Verarbeitung der Daten unerheblich. Die Videoaufnahmen werden nach der Studie von uns
|
||||||
|
ausgewertet und soweit wie möglich als Text ausgeschrieben.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Rechtsgrundlage der Verarbeitung
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Die Verarbeitung der personenbezogenen Daten im Rahmen dieser Studie ist rechtmäßig, weil die
|
||||||
|
betroffenen Personen in die Verarbeitung einwilligen (Art. 6 Abs. 1, lit. a EU-DSGVO) oder weil die
|
||||||
|
Verarbeitung für die wissenschaftlichen Forschungszwecke im Bereich des Affective Computing erforderlich
|
||||||
|
ist und die Interessen der betroffenen Personen nicht überwiegen (Art. 6 Abs. 1, lit. e und f EU-DSGVO).
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Empfänger
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Unter der unmittelbaren Verantwortung des DFKI können die personenbezogenen Daten ausschließlich nach
|
||||||
|
Anonymisierung veröffentlicht oder an Forschungspartner für deren wissenschaftliche Forschungszwecke im
|
||||||
|
Bereich des Affective Computing übermittelt werden. Personenbezogene Daten werden nicht an
|
||||||
|
Auftragsverarbeiter oder andere Empfänger übermittelt, auch nicht zur Löschung oder Vernichtung.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Keine automatisierte Entscheidungsfindung
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Die personenbezogenen Daten werden nicht für eine automatisierte Entscheidungsfindung einschließlich
|
||||||
|
Profiling verwendet.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Dauer der Speicherung
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Die personenbezogenen Daten werden grundsätzlich für die Dauer der Forschungsprojekte im Bereich des
|
||||||
|
Affective Computing gespeichert. Sie sollen anonymisiert veröffentlicht werden. Nach der Anonymisierung
|
||||||
|
ist kein Rückschluss aus den Daten auf die Identität der Person möglich.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Transparenz und Intervention
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Zur Gewährleistung einer transparenten und fairen Verarbeitung im Rahmen dieser Studie bestehen für
|
||||||
|
betroffene Personen die folgenden Rechte:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Das Recht auf Auskunft über die personenbezogenen Daten</li>
|
||||||
|
<li>Das Recht auf Berichtigung und Vervollständigung der personenbezogenen Daten</li>
|
||||||
|
<li>Das Recht auf Löschung der personenbezogenen Daten</li>
|
||||||
|
<li>Das Recht auf Einschränkung der Verarbeitung der personenbezogenen Daten</li>
|
||||||
|
<li>Das Recht auf Widerruf einer erteilten Einwilligung</li>
|
||||||
|
<li>Das Recht auf Widerspruch gegen die Verarbeitung der personenbezogenen Daten</li>
|
||||||
|
</ul>
|
||||||
|
<h3>
|
||||||
|
Recht auf Beschwerde
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Betroffene Personen haben das Recht auf Beschwerde bei einer Aufsichtsbehörde, wenn sie der Ansicht
|
||||||
|
sind, dass die Verarbeitung ihrer personenbezogenen Daten durch diese Studie gegen gesetzliche
|
||||||
|
Datenschutzvorschriften verstößt.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Einwilligung betroffener Personen zur Veröffentlichung personenbezogener Daten und zu deren Übermittlung
|
||||||
|
an Forschungspartner
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
In dieser Studie werden verschiedene personenbezogene Informationen erhoben. Die Daten werden
|
||||||
|
ausschließlich durch das DFKI und Forschungspartner im Rahmen wissenschaftlicher Forschungsprojekte
|
||||||
|
verarbeitet. Alle weiteren personenbezogenen Daten werden nur anonymisiert gespeichert und im Rahmen
|
||||||
|
einer wissenschaftlichen Arbeit veröffentlicht.
|
||||||
|
</p>
|
||||||
|
<h3>
|
||||||
|
Einwilligung zur Veröffentlichung und Übermittlung
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
Ich bestätige, dass ich die „Information betroffener Personen zur Verarbeitung personenbezogener Daten“
|
||||||
|
erhalten habe.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Ich willige hiermit ein, dass das DFKI Daten aus wissenschaftlichen Experimenten im Zusammenhang mit
|
||||||
|
dieser Studie für die Darstellung von Forschungsergebnissen im Bereich des Affective Computing verwendet.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Mir ist bekannt, dass ich das Recht habe, meine Einwilligung jederzeit zu widerrufen. Durch den Widerruf
|
||||||
|
der Einwilligung wird die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten
|
||||||
|
Verarbeitung nicht berührt. Ein Widerruf kann per Email an avatarstudy@proton.me geschickt werden.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
||||||
65
slaeforms/templates/dqinfos.html
Normal file
65
slaeforms/templates/dqinfos.html
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<div style="margin: auto; max-width: 80%;">
|
||||||
|
<p>Demografische Fragen:</p>
|
||||||
|
<ol start="1">
|
||||||
|
<li>Wie alt sind sie?</li>
|
||||||
|
<li>Wie ist ihr Geschlecht?
|
||||||
|
<ol>
|
||||||
|
<li>Männlich</li>
|
||||||
|
<li>Weiblich</li>
|
||||||
|
<li>Divers</li>
|
||||||
|
<li>Keine Angabe</li>
|
||||||
|
</ol></li>
|
||||||
|
<li>Was ist ihr höchster Bildungsabschluss?
|
||||||
|
<ol>
|
||||||
|
<li>Keiner</li>
|
||||||
|
<li>Hauptschule</li>
|
||||||
|
<li>Realschule</li>
|
||||||
|
<li>Ausbildung</li>
|
||||||
|
<li>Abitur</li>
|
||||||
|
<li>Fachhochschulreife</li>
|
||||||
|
<li>Bachelor</li>
|
||||||
|
<li>Master</li>
|
||||||
|
<li>Diplom</li>
|
||||||
|
<li>Magister</li>
|
||||||
|
<li>Promotion</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>Wie ist ihr Hörstatus?
|
||||||
|
<ol>
|
||||||
|
<li>Gehörlos</li>
|
||||||
|
<li>Schwerhörig</li>
|
||||||
|
<li>Gehörlos mit Cochlea-Implantat</li>
|
||||||
|
<li>Hörend</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>In welchem Alter wurden sie gehörlos/schwerhörig? ("0" für ab Geburt, "-1" falls sie hörend sind)</li>
|
||||||
|
<li>Seit welchem Alter lernen sie Gebärdensprache?</li>
|
||||||
|
<li>Sind ihre Eltern Gehörlos?
|
||||||
|
<ol>
|
||||||
|
<li>Ein Elternteil</li>
|
||||||
|
<li>Beide</li>
|
||||||
|
<li>Nein</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>Welche Sprache(n) verwenden sie zuhause?
|
||||||
|
<ol>
|
||||||
|
<li>Deutsch</li>
|
||||||
|
<li>Gebärdensprache</li>
|
||||||
|
<li>Sonstige</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>Welche Sprache(n) verwenden sie auf der Arbeit/in der Schule?
|
||||||
|
<ol>
|
||||||
|
<li>Deutsch</li>
|
||||||
|
<li>Gebärdensprache</li>
|
||||||
|
<li>Sonstige</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>Haben sie schonmal Computeranimationen von Gebärdensprache gesehen? (Gebärdensprachavatare)
|
||||||
|
<ol>
|
||||||
|
<li>Ja</li>
|
||||||
|
<li>Nein</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
@@ -1,22 +1,36 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
<title>DGS Avatar Study</title>
|
<title>DGS Avatar Study</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>Thank you for participating in our study!</h2>
|
<h2>Vielen Dank für Ihre Teilnahme!</h2>
|
||||||
|
|
||||||
<div class="textblock">
|
<div class="textblock">
|
||||||
<p>
|
<p>
|
||||||
If you liked this study, we would be grateful if you share it and invite other people to also participate.
|
Die Studie ist nun beendet und Sie können die Seite verlassen.
|
||||||
Anyone with some level of sign language understanding can participate.
|
</p>
|
||||||
If you have further questions, please send an email to testemail@notarealemail.deee
|
<p>
|
||||||
|
Wir würden uns freuen, wenn Sie die Studie mit anderen Gehörlosen oder Personen, die Gebärdensprache
|
||||||
|
sprechenden, teilen würden: <a href="https://slaeforms.leafbla.de/start">https://slaeforms.leafbla.de/start</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Falls Sie noch Fragen oder Anmerkungen haben, schreiben Sie uns unter: avatarstudy@proton.me
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
</html>
|
</html>
|
||||||
53
slaeforms/templates/impressum.html
Normal file
53
slaeforms/templates/impressum.html
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container" style="height: 100%; font-size: 22px;">
|
||||||
|
<h2>Impressum</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
<p>
|
||||||
|
Datenschutzerklärung: <a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Verantwortlicher für slaeforms.leafbla.de: Jan Dickmann, zusammen mit dem DFKI Saarbrücken, Affective Computing Group
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Adresse:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Deutsches Forschungszentrum für Künstliche Intelligenz GmbH (DFKI)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Stuhlsatzenhausweg 3
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Saarland Informatics Campus D 3_2
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
66123 Saarbrücken
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
avatarstudy@proton.me
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:50px"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
||||||
47
slaeforms/templates/intropage.html
Normal file
47
slaeforms/templates/intropage.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h2>SLAEFORMS Gebärdensprachavatar Studie</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
|
||||||
|
<p style="font-size: 22px;">
|
||||||
|
Bei allen Aufgaben in dieser Studie gibt es Texte, in denen die Aufgaben und die Antwortmöglichkeiten erklärt werden.
|
||||||
|
Falls Sie Fragen haben oder eine Aufgabe nicht verstehen, können Sie den "Info"-Button auf der rechten Seite des Bildschirms klicken, um den Erklärtext zu sehen.
|
||||||
|
Sie können den Button nochmal anklicken, um wieder zur Aufgabe zurückzukommen.
|
||||||
|
</p>
|
||||||
|
<div style="margin: auto; display: block; max-width: 90px;">
|
||||||
|
<button style="margin: auto; max-width: 90px;"><img class="infoButtonIcon" id="buttonInfoIcon"
|
||||||
|
src="{{ url_for('static', filename='icons/info-icon.png')}}" alt="info-icon"></button>
|
||||||
|
</div>
|
||||||
|
<p style="font-size: 22px; text-align: center;">
|
||||||
|
Das ist der Info-Button.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<form class="dsgvoform" action="{{ url_for('sendpage') }}" method="post">
|
||||||
|
<div class="button-container">
|
||||||
|
<button id="submitbutton" type="submit">Starten</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:80px"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
||||||
21
slaeforms/templates/login.html
Normal file
21
slaeforms/templates/login.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<title>Login Page</title>
|
||||||
|
<link rel="shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="login-container" >
|
||||||
|
<p>Some pages require you to be logged in.</p>
|
||||||
|
<form action="{{ url_for('login') }}" method="post">
|
||||||
|
<input class="login-elements" type="password" value="" name="password" placeholder="password">
|
||||||
|
<input class="login-elements" id="loginbutton" type="submit" value="submit";/>
|
||||||
|
</form></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
52
slaeforms/templates/manage_uploads.html
Normal file
52
slaeforms/templates/manage_uploads.html
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container" style="height: 100%; font-size: 22px;">
|
||||||
|
<h2>Upload management</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
<p>
|
||||||
|
Anzahl Videos: {{ num_videos }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Die aktuellen Videos:
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for video in videolist %}
|
||||||
|
<p>{{video}}</p>
|
||||||
|
{% endfor %}
|
||||||
|
<div class="textblock">
|
||||||
|
<p>
|
||||||
|
Download <a href="{{ url_for('export_all_videos') }}" target="_blank">hier</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<form class="dsgvoform" action="{{ url_for('deleteuploads') }}" method="post">
|
||||||
|
<label for="terms-and-conditions">
|
||||||
|
<input class="inline" id="terms-and-conditions" type="checkbox" required name="terms-and-conditions" />
|
||||||
|
Alle Videos löschen.
|
||||||
|
</label>
|
||||||
|
<div class="button-container">
|
||||||
|
<button id="submitbutton" type="submit">Löschen</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:50px"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</html>
|
||||||
77
slaeforms/templates/oldstart.html
Normal file
77
slaeforms/templates/oldstart.html
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h2>SLAEFORMS Gebärdensprachavatar Studie</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
|
||||||
|
|
||||||
|
<div style="margin: auto; font-size: 20px;">
|
||||||
|
<p>
|
||||||
|
Hallo und willkommen zu dieser Studie, danke für Ihre Teilnahme.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In dieser Studie geht es um die Entwicklung von Gebärdensprachavataren.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Bitte beachten Sie, dass diese Avatare noch in einer frühen Entwicklungsphase und noch nicht für den
|
||||||
|
Gebrauch in einer App/einem Computerprogramm oder auf einer Webseite geeignet sind. In dieser Studie
|
||||||
|
geht es darum, einzelne Aspekte der Avatare und neue technologische Ansätze zu testen. Dementsprechend
|
||||||
|
haben die Avatare noch viele offensichtliche Schwächen, wie zum Beispiel, dass bisher nur die Arme und
|
||||||
|
der Oberkörper, aber nicht das Gesicht animiert ist. Bitte bewerten Sie nur die Qualität der Hände und
|
||||||
|
Arme.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Diese Studie richtet sich an Menschen, die Gebärdensprache beherrschen, insbesondere gehörlose Menschen.
|
||||||
|
Nehmen Sie bitte nur Teil, wenn Sie (Deutsche) Gebärdensprache beherrschen.
|
||||||
|
Die Studie dauert ca. 20 Minuten.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Während der Studie werden sie sich Videos anschauen, diese bewerten und Feedback dazu geben können.
|
||||||
|
Verwenden Sie deshalb bitte, wenn möglich ein Gerät mit einem großen Bildschirm (Laptop, PC, Tablet) für
|
||||||
|
Ihre Teilnahme, damit Sie die Videos in ausreichender Größe sehen können.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Sie haben während der Studie die Möglichkeit (optional) Videofeedback zu geben, dazu brauchen sie eine
|
||||||
|
Webcam. Die Videos werden nicht veröffentlicht und nur Übersetzern zur Auswertung der Studienergebnisse
|
||||||
|
gezeigt.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Das Laden der Seiten kann manchmal einige Sekunden dauern. Falls es zu einem Fehler kommen sollte und ein Video nicht geladen wird, versuchen Sie bitte die Seite neu zu laden.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Für jeden Teil der Studie gibt es einen Text, der die Fragestellung und die Antwortmöglichkeiten erklärt. Falls Sie den Text während der Studie nochmal sehen möchten, können Sie es
|
||||||
|
über den „Info“-Knopf auf der rechten Seite aufrufen.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Bitte versuchen sie während der Studie nicht auf die vorherige Seite "zurück" zu gehen, da sie nicht zu vorherigen Fragen zurück können.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<form class="dsgvoform" action="{{ url_for('sendpage') }}" method="post">
|
||||||
|
<div class="button-container">
|
||||||
|
<button id="submitbutton" type="submit">Weiter</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:80px"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</html>
|
||||||
9
slaeforms/templates/p1infos.html
Normal file
9
slaeforms/templates/p1infos.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<div style="margin: auto; max-width: 80%; font-size: 20px;">
|
||||||
|
<p>Studie Teil 1:</p>
|
||||||
|
<p>Im Folgenden werden Ihnen Videos gezeigt, die Sie in den Kategorien „Natürlichkeit“, „Verständlichkeit“ und „grammatikalischer Korrektheit“ bewerten sollen.</p>
|
||||||
|
<p>Dafür können Sie auf einer Skala mit 7 Punkten bewerten, wobei der Punkt ganz links für „Sehr schlecht“, der Punkt in der Mitte für "Weder gut noch schlecht", und der Punkt ganz rechts für „Sehr gut“ steht.</p>
|
||||||
|
<p>Dann können Sie weiteres Feedback als Text oder als Video geben. Das Video können Sie direkt im Browser aufnehmen. Beachten Sie, dass sie dazu eine Webcam benötigen und der Webseite erlauben müssen diese zu benutzen. Wenn Sie auf den Kamera-Knopf drücken, wird ihr Browser Sie nach der Berechtigung fragen.</p>
|
||||||
|
<p>Videoaufnahmen können maximal 70 Sekunden lang sein, dann wird die Aufnahme automatisch beendet.</p>
|
||||||
|
<p>Wenn Sie Feedback als Video geben, kann es einige Sekunden dauern die nächste Seite aufzurufen, weil das Video erst hochgeladen werden muss.</p>
|
||||||
|
<p>Genaue Informationen darüber, wie wir die Videos verarbeiten, finden Sie in unserer <a target="_blank" href="{{ url_for('datenschutz') }}">Datenschutzerklärung</a>.</p>
|
||||||
|
</div>
|
||||||
35
slaeforms/templates/p1intro.html
Normal file
35
slaeforms/templates/p1intro.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h2>SLAEFORMS Gebärdensprachavatar Studie</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
|
||||||
|
{% include "p1infos.html" %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<form class="dsgvoform" action="{{ url_for('sendpage') }}" method="post">
|
||||||
|
<div class="button-container">
|
||||||
|
<button id="submitbutton" type="submit">Weiter</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:80px"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</html>
|
||||||
20
slaeforms/templates/p2infos.html
Normal file
20
slaeforms/templates/p2infos.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<div style="margin: auto; max-width: 80%; font-size: 20px;">
|
||||||
|
<p>Studie Teil 2:</p>
|
||||||
|
<p>Im Folgenden sehen Sie zwei Videos, in denen der gleiche Satz mit unterschiedlichen Formulierungen gebärdet wird.</p>
|
||||||
|
<p>Der folgende Satz wird gebärdet: Einfahrt RE 77 Richtung Köln Hauptbahnhof über Hannover, Abfahrt 3:44 Uhr.</p>
|
||||||
|
<p>Bitte verwenden Sie die Punkteskala, um zu bewerten, welches der beiden Videos Sie besser finden.</p>
|
||||||
|
<ol start="1">
|
||||||
|
<li>Welche Formulierung war natürlicher?</li>
|
||||||
|
<li>Welche Formulierung haben Sie besser verstanden?</li>
|
||||||
|
<li>Welche Formulierung war korrekter?</li>
|
||||||
|
<li>Welche Formulierung hat Ihnen besser gefallen?</li>
|
||||||
|
</ol>
|
||||||
|
<p>Die Antwortmöglichkeiten sind jedes Mal:</p>
|
||||||
|
<ol start="1">
|
||||||
|
<li>Links</li>
|
||||||
|
<li>Eher links</li>
|
||||||
|
<li>Beide gleich</li>
|
||||||
|
<li>Eher rechts</li>
|
||||||
|
<li>Rechts</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
35
slaeforms/templates/p2intro.html
Normal file
35
slaeforms/templates/p2intro.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h2>SLAEFORMS Gebärdensprachavatar Studie</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
|
||||||
|
{% include "p2infos.html" %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<form class="dsgvoform" action="{{ url_for('sendpage') }}" method="post">
|
||||||
|
<div class="button-container">
|
||||||
|
<button id="submitbutton" type="submit">Weiter</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:80px"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</html>
|
||||||
20
slaeforms/templates/p3infos.html
Normal file
20
slaeforms/templates/p3infos.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<div style="margin: auto; max-width: 80%; font-size: 20px;">
|
||||||
|
<p>Studie Teil 3:</p>
|
||||||
|
<p>Im Folgenden sehen Sie ein Video, in dem der Avatar drei Mal „Gleis“ gebärdet, jedes Mal in eine etwas andere Richtung. So soll der Avatar in Zukunft die Position und Richtung des Gleises relativ zum Avatar und Zuschauer zum Ausdruck bringen.</p>
|
||||||
|
<p>
|
||||||
|
Bewerten Sie bitte die folgenden Aussagen auf einer Skala mit fünf Punkten, von „Trifft überhaupt nicht zu“, bis „Trifft vollkommen zu“.</p>
|
||||||
|
<ol start="1">
|
||||||
|
<li>Man kann gut erkennen, in welche Richtung das Gleis zeigt.</li>
|
||||||
|
<li>Die Gebärde ist schwer zu erkennen.</li>
|
||||||
|
<li>Das Anpassen der Richtung und der Position der Gebärde kann dabei helfen, besser zu verstehen, wo das Gleis liegt.</li>
|
||||||
|
<li>Ich finde diesen Ansatz nicht gut.</li>
|
||||||
|
</ol>
|
||||||
|
<p>Die Antwortmöglichkeiten sind jedes Mal:</p>
|
||||||
|
<ol start="1">
|
||||||
|
<li>Trifft überhaupt nicht zu</li>
|
||||||
|
<li>Trifft eher nicht zu</li>
|
||||||
|
<li>Ich weiß nicht</li>
|
||||||
|
<li>Trifft eher zu</li>
|
||||||
|
<li>Trifft vollkommen zu</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
35
slaeforms/templates/p3intro.html
Normal file
35
slaeforms/templates/p3intro.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<title>DGS Avatar Study</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h2>SLAEFORMS Gebärdensprachavatar Studie</h2>
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
|
||||||
|
{% include "p3infos.html" %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<form class="dsgvoform" action="{{ url_for('sendpage') }}" method="post">
|
||||||
|
<div class="button-container">
|
||||||
|
<button id="submitbutton" type="submit">Weiter</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:80px"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</html>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<button class="dialogBtn" autofocus><img class="infoButtonIcon" id="buttonClose" src="{{ url_for('static', filename='icons/x-icon.png')}}"
|
<button class="dialogBtn" autofocus><img class="infoButtonIcon" id="buttonClose" src="{{ url_for('static', filename='icons/x-icon.png')}}"
|
||||||
alt="Delete Icon"></button>
|
alt="Delete Icon"></button>
|
||||||
<div class="iframe-container">
|
<div class="iframe-container">
|
||||||
<iframe class="center" src="https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522" title="YouTube video player" frameborder="0"
|
<iframe class="center" src="https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh" title="YouTube video player" frameborder="0"
|
||||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
allowfullscreen></iframe>
|
allowfullscreen></iframe>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
If you have further questions, please send an email to testemail@notarealemail.deee
|
If you have further questions, please send an email to testemail@notarealemail.deee
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<form class="dsgvoform" action="http://localhost:5000/start" method="post">
|
<form class="dsgvoform" action="{{ url_for('startpage') }}" method="post">
|
||||||
<label for="terms-and-conditions">
|
<label for="terms-and-conditions">
|
||||||
<input class="inline" id="terms-and-conditions" type="checkbox" required name="terms-and-conditions" /> I accept the +terms and conditions
|
<input class="inline" id="terms-and-conditions" type="checkbox" required name="terms-and-conditions" /> I accept the +terms and conditions
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -13,6 +13,19 @@
|
|||||||
allowfullscreen></iframe>
|
allowfullscreen></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% elif (embed == "vimeo") %}
|
||||||
|
<div class="iframe-container">
|
||||||
|
|
||||||
|
<iframe title="vimeo-player" class="center" src="{{ video_url }}" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% elif (embed == "no") %}
|
||||||
|
|
||||||
|
<video controls>
|
||||||
|
<source src="{{ url_for('static', filename='videos/' + video_url) }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{{code}}
|
{{code}}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -36,8 +49,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="dv_button">Play Videos</button>
|
|
||||||
|
|
||||||
<div class="dv_half">
|
<div class="dv_half">
|
||||||
<div class="iframe-container">
|
<div class="iframe-container">
|
||||||
<iframe class="center" src="{{ video_url2 }}" title="YouTube video player" frameborder="0"
|
<iframe class="center" src="{{ video_url2 }}" title="YouTube video player" frameborder="0"
|
||||||
@@ -48,6 +59,42 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% elif (embed == "vimeo") %}
|
||||||
|
<div class="double_video_container">
|
||||||
|
|
||||||
|
<div class="dv_half">
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe title="vimeo-player" class="center" src="{{ video_url1 }}" frameborder="0" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dv_half">
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe title="vimeo-player" class="center" src="{{ video_url2 }}" frameborder="0" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% elif (embed == "no") %}
|
||||||
|
<div class="double_video_container">
|
||||||
|
<div class="dv_half">
|
||||||
|
<div class="iframe-container">
|
||||||
|
<video controls>
|
||||||
|
<source src="{{ url_for('static', filename='videos/' + video_url1) }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dv_half">
|
||||||
|
<div class="iframe-container">
|
||||||
|
<video controls>
|
||||||
|
<source src="{{ url_for('static', filename='videos/' + video_url2) }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{code}}
|
{{code}}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -73,7 +120,7 @@ step={{question["step"]}}
|
|||||||
|
|
||||||
{% macro input(name, value='', type='text', size=20) -%}
|
{% macro input(name, value='', type='text', size=20) -%}
|
||||||
<input type="{{ type }}" name="{{ name }}" value="{{
|
<input type="{{ type }}" name="{{ name }}" value="{{
|
||||||
value|e }}" size="{{ size }}">
|
value|e }}" size="{{ size }}" class="inputs">
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
@@ -81,7 +128,7 @@ step={{question["step"]}}
|
|||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}" />
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}" />
|
||||||
<!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
<!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
<title>Testform</title>
|
<title>Testform</title>
|
||||||
<link rel=" shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
<script>const ICON_PATHS = {
|
<script>const ICON_PATHS = {
|
||||||
cameraofficon: "{{ url_for('static', filename='icons/camera-off-icon.png') }}",
|
cameraofficon: "{{ url_for('static', filename='icons/camera-off-icon.png') }}",
|
||||||
cameraicon: "{{ url_for('static', filename='icons/camera-icon.png') }}",
|
cameraicon: "{{ url_for('static', filename='icons/camera-icon.png') }}",
|
||||||
@@ -92,6 +139,32 @@ step={{question["step"]}}
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
|
{% if (infovideo) %}
|
||||||
|
<dialog>
|
||||||
|
|
||||||
|
<button class="dialogBtn" autofocus><img class="infoButtonIcon" id="buttonClose"
|
||||||
|
src="{{ url_for('static', filename='icons/x-icon.png')}}" alt="Delete Icon"></button>
|
||||||
|
{% if ("videourl" in infovideo) %}
|
||||||
|
<video controls>
|
||||||
|
<source src="{{ url_for('static', filename=infovideo['videourl']) }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
{% endif %}
|
||||||
|
<div class="dialogTextContainer">
|
||||||
|
{% if ("infotext" in infovideo) %}
|
||||||
|
<p>{{ infovideo["infotext"] }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if ("htmlblock" in infovideo) %}
|
||||||
|
{% include infovideo["htmlblock"] %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<button class="dialogBtn"><img class="infoButtonIcon" id="buttonInfoIcon"
|
||||||
|
src="{{ url_for('static', filename='icons/info-icon.png')}}" alt="Info Icon"></button>
|
||||||
|
<script src="{{ url_for('static', filename='infoDialogScript.js')}}"></script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% if (stimulus_type == "single_video") %}
|
{% if (stimulus_type == "single_video") %}
|
||||||
{{ single_video(**stimulus_configuration) }}
|
{{ single_video(**stimulus_configuration) }}
|
||||||
{% elif (stimulus_type == "double_video") %}
|
{% elif (stimulus_type == "double_video") %}
|
||||||
@@ -102,16 +175,28 @@ step={{question["step"]}}
|
|||||||
<p>Error: Block {{ stimulus["type"] }} could not be loaded!</p>
|
<p>Error: Block {{ stimulus["type"] }} could not be loaded!</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form class="formlayout" id="question_form" action="http://localhost:5000/send" method="post">
|
<form class="formlayout" id="question_form" action="{{ url_for('sendpage') }}" method="post">
|
||||||
|
|
||||||
{% for question in questions %}
|
{% for question in questions %}
|
||||||
{% if (questions[question]["type"] == "likert") %}
|
{% if (questions[question]["type"] == "textblock") %}
|
||||||
<div class="likercontainer">
|
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
|
<div class="questioncontainer">
|
||||||
|
<h3 style="margin: auto;">{{ questions[question]['text']}}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:60px"></div>
|
||||||
|
|
||||||
|
|
||||||
|
{% elif (questions[question]["type"] == "likert") %}
|
||||||
|
<div class="likertcontainer">
|
||||||
|
<div class="questioncontainer">
|
||||||
<h3>{{ questions[question]['text']}}</h3>
|
<h3>{{ questions[question]['text']}}</h3>
|
||||||
|
</div>
|
||||||
<div class="likert" style="--likert-rows: {{ questions[question]['points']|length() }}">
|
<div class="likert" style="--likert-rows: {{ questions[question]['points']|length() }}">
|
||||||
{% for point in questions[question]["points"] %}
|
{% for point in questions[question]["points"] %}
|
||||||
<label>
|
<label>
|
||||||
<input name="{{ questions[question]['name']}}" type="radio"
|
<input class="inputs" name="{{ questions[question]['name']}}" type="radio"
|
||||||
id="{{ questions[question]['name'] }}"
|
id="{{ questions[question]['name'] }}"
|
||||||
value="{{ questions[question]['points'][point]['value'] }}"
|
value="{{ questions[question]['points'][point]['value'] }}"
|
||||||
{{required(questions[question])}} /><span>{{ questions[question]['points'][point]['text']
|
{{required(questions[question])}} /><span>{{ questions[question]['points'][point]['text']
|
||||||
@@ -120,45 +205,73 @@ step={{question["step"]}}
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:60px"></div>
|
||||||
|
|
||||||
|
{% elif (questions[question]["type"] == "likert-basic") %}
|
||||||
|
|
||||||
|
<div class="questioncontainer">
|
||||||
|
<h3>{{ questions[question]['text']}}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="normal-likert-container">
|
||||||
|
{% for point in questions[question]["points"] %}
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="{{ questions[question]['name']}}" type="radio"
|
||||||
|
id="{{ questions[question]['name'] }}"
|
||||||
|
value="{{ questions[question]['points'][point]['value'] }}"
|
||||||
|
{{required(questions[question])}} /><span>{{ questions[question]['points'][point]['text']
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:60px"></div>
|
||||||
|
|
||||||
{% elif (questions[question]["type"] == "textinput") %}
|
{% elif (questions[question]["type"] == "textinput") %}
|
||||||
<div class="textarea-container">
|
<div class="textarea-container">
|
||||||
<label class="textarea-label">
|
<label class="textarea-label">
|
||||||
{{ questions[question]['text']}}
|
{{ questions[question]['text']}}
|
||||||
<textarea id="{{ questions[question]['name'] }}" name="{{ questions[question]['name'] }}" rows="6"
|
<textarea class="inputs" id="{{ questions[question]['name'] }}"
|
||||||
cols="60" maxlength="{{ questions[question]['size'] }}"
|
name="{{ questions[question]['name'] }}" rows="6" cols="60"
|
||||||
{{required(questions[question])}}></textarea>
|
maxlength="{{ questions[question]['size'] }}" {{required(questions[question])}}></textarea>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
{% elif (questions[question]["type"] == "dateinput") %}
|
{% elif (questions[question]["type"] == "dateinput") %}
|
||||||
<div class="compressWidth">
|
<div class="compressWidth">
|
||||||
<label>
|
<label>
|
||||||
{{ questions[question]['text']}}<input type="date" name="{{ questions[question]['name']}}"
|
{{ questions[question]['text']}}<input class="inputs" type="date"
|
||||||
id="{{ questions[question]['name'] }}" {{required(questions[question])}}>
|
name="{{ questions[question]['name']}}" id="{{ questions[question]['name'] }}"
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
{% elif (questions[question]["type"] == "numberinput") %}
|
|
||||||
<div class="compressWidth">
|
|
||||||
<label>
|
|
||||||
{{ questions[question]['text']}}<input type="number" name="{{ questions[question]['name']}}"
|
|
||||||
id="{{ questions[question]['name'] }}" {{inputconfig(questions[question])}}
|
|
||||||
{{required(questions[question])}}>
|
{{required(questions[question])}}>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
|
{% elif (questions[question]["type"] == "numberinput") %}
|
||||||
|
<div class="compressWidth">
|
||||||
|
<label>
|
||||||
|
{{ questions[question]['text']}}<input class="inputs" type="number"
|
||||||
|
name="{{ questions[question]['name']}}" id="{{ questions[question]['name'] }}"
|
||||||
|
{{inputconfig(questions[question])}} {{required(questions[question])}}>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
{% elif (questions[question]["type"] == "emailinput") %}
|
{% elif (questions[question]["type"] == "emailinput") %}
|
||||||
<div class="compressWidth">
|
<div class="compressWidth">
|
||||||
<label>
|
<label>
|
||||||
{{ questions[question]['text']}}<input type="email" name="{{ questions[question]['name']}}"
|
{{ questions[question]['text']}}<input class="inputs" type="email"
|
||||||
id="{{ questions[question]['name'] }}" {{required(questions[question])}}>
|
name="{{ questions[question]['name']}}" id="{{ questions[question]['name'] }}"
|
||||||
|
{{required(questions[question])}}>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
{% elif (questions[question]["type"] == "dropdowninput") %}
|
{% elif (questions[question]["type"] == "dropdowninput") %}
|
||||||
<div class="compressWidth">
|
<div class="compressWidth">
|
||||||
<label>
|
<label>
|
||||||
{{ questions[question]['text']}}<select name="{{ questions[question]['name']}}"
|
{{ questions[question]['text']}}<select class="inputs" name="{{ questions[question]['name']}}"
|
||||||
{{required(questions[question])}}>
|
{{required(questions[question])}}>
|
||||||
<option value="" disabled selected>{{ questions[question]['defaulttext']}}</option>
|
<option value="" disabled selected>{{ questions[question]['defaulttext']}}</option>
|
||||||
{% for point in questions[question]["points"] %}
|
{% for point in questions[question]["points"] %}
|
||||||
@@ -171,11 +284,29 @@ step={{question["step"]}}
|
|||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
|
{% elif (questions[question]["type"] == "multiplechoice") %}
|
||||||
|
<div class="compressWidth">
|
||||||
|
<p>
|
||||||
|
<div>
|
||||||
|
{{ questions[question]['text']}}
|
||||||
|
|
||||||
|
{% for point in questions[question]["points"] %}
|
||||||
|
<label for="{{ point }}">
|
||||||
|
<input type="checkbox" id="{{ point }}" name="{{ questions[question]['name'] }}"
|
||||||
|
value="{{ questions[question]['points'][point]['value'] }}">
|
||||||
|
{{ questions[question]['points'][point]['text']}}</label>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
{% elif (questions[question]["type"] == "videoinput") %}
|
{% elif (questions[question]["type"] == "videoinput") %}
|
||||||
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
<h2>Gib Feedback als Video</h2>
|
<h3 style="text-align: center;">{{ questions[question]['text']}}</h3>
|
||||||
<h3>{{ questions[question]['text']}}</h3>
|
|
||||||
|
|
||||||
<div class="centertext">
|
<div class="centertext">
|
||||||
<button type="button" class="videocontrols" id="buttonCamera" onclick="cameraButton()">
|
<button type="button" class="videocontrols" id="buttonCamera" onclick="cameraButton()">
|
||||||
@@ -205,19 +336,36 @@ step={{question["step"]}}
|
|||||||
<video autoplay muted playsinline id="videoDisplay"></video>
|
<video autoplay muted playsinline id="videoDisplay"></video>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="{{ url_for('static', filename='videoscript.js')}}">
|
<p id="countdown" style="font-size: 40px; text-align: center;"></p>
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='videoscript.js')}}">
|
||||||
</script>
|
</script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Error: Block {{config["question 1"]["blocks"][block]["type"]}} could not be loaded!</p>
|
<p>Error: Block {{config["question 1"]["blocks"][block]["type"]}} could not be loaded!</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<input id="submitbutton" type="submit" value="submit" />
|
|
||||||
<!-- TODO maybe I want to use this instead: <button id="submitbutton" type="submit">Submit</button> -->
|
{% if ("lastquestion" in stimlui) %}
|
||||||
|
<button id="submitbutton" type="submit">Studie Beenden</button>
|
||||||
|
<!-- TODO maybe I want to use this instead: <button id="submitbutton" type="submit">Submit</button> /// <input class="inputs" id="submitbutton" type="submit" value="submit" />-->
|
||||||
|
{% else %}
|
||||||
|
<button id="submitbutton" type="submit">Weiter</button>
|
||||||
|
<!-- TODO maybe I want to use this instead: <button id="submitbutton" type="submit">Submit</button> /// <input class="inputs" id="submitbutton" type="submit" value="submit" />-->
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:80px"></div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -4,20 +4,69 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
<title>DGS Avatar Study</title>
|
<title>DGS Avatar Study</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container" style="height: 100%; font-size: 22px;">
|
||||||
<h2>Hello! Thank you for participating in our study!</h2>
|
<h2>SLAEFORMS Gebärdensprachavatar Studie</h2>
|
||||||
<form action="http://localhost:5000/start" method="post">
|
|
||||||
<label for="terms-and-conditions">
|
|
||||||
<input class="inline" id="terms-and-conditions" type="checkbox" required name="terms-and-conditions" /> I accept the +terms and conditions</a>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<p><input id="submitbutton" type = "submit" value = "submit" /></p>
|
<div class="iframe-container2">
|
||||||
|
|
||||||
|
<iframe title="vimeo-player" src="https://player.vimeo.com/video/1031133490?h=bfa5b559f9" frameborder="0"
|
||||||
|
allowfullscreen></iframe>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="textblock">
|
||||||
|
<p>
|
||||||
|
Hallo und willkommen zu dieser Studie, danke für Ihre Teilnahme.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In dieser Studie geht es um die Entwicklung von Gebärdensprachavataren.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Bitte berücksichtige, dass die Avatare, die wir zeigen, in keiner Weise der Qualität entsprechen, wie
|
||||||
|
sie genutzt werden sollen. Sie sind nur Beispiele, die niemals in einer Anwendung zu sehen sein werden.
|
||||||
|
Es geht darum, dass wir die Darstellung der Hände und Arme testen wollen. Bitte bewertet deshalb nicht
|
||||||
|
Darstellungsqualität und lasst euch nicht davon beeinflussen. Außerdem möchten wir testen, wie die
|
||||||
|
Nutzung einer Feedback-Funktion per Videoaufnahme verwendet werden kann.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Die Rückmeldung von euch ist wichtig und ihr könnt das in Gebärdensprache machen.
|
||||||
|
Die Teilnahme wird nur für die Auswertung genutzt. In keiner Weise wird etwas von euch veröffentlicht, auch nicht eure Videos.
|
||||||
|
Alle weiteren Infos findet ihr im Text.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Danke für eure Teilnahme, die im Rahmen eine Abschlussarbeit erfolgt. Weitere Infos dazu findet ihr im Impressum.
|
||||||
|
</p>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:20px"></div>
|
||||||
|
<p>
|
||||||
|
Die Teilnahme an dieser Studie ist komplett freiwillig, Sie können die Studie zu jedem Zeitpunkt
|
||||||
|
abbrechen, indem Sie die Seite einfach schließen. Sie können außerdem die Löschung aller Daten bei uns
|
||||||
|
beantragen: avatarstudy@proton.me
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<form class="dsgvoform" action="{{ url_for('startpage') }}" method="post">
|
||||||
|
<label for="terms-and-conditions">
|
||||||
|
<input class="inline" id="terms-and-conditions" type="checkbox" required name="terms-and-conditions" />
|
||||||
|
Ich akzeptiere die <a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutzbestimmungen</a>
|
||||||
|
</label>
|
||||||
|
<div class="button-container">
|
||||||
|
<button id="submitbutton" type="submit">Weiter</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:50px"></div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
<footer>
|
||||||
|
<div class="container" style="font-size: 19px;">
|
||||||
|
<a href="{{ url_for('startpage') }}" target="_blank">Startseite</a>
|
||||||
|
<a href="{{ url_for('impressum') }}" target="_blank">Impressum</a>
|
||||||
|
<a href="{{ url_for('datenschutz') }}" target="_blank">Datenschutz</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
157
slaeforms/templates/studytest.html
Normal file
157
slaeforms/templates/studytest.html
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}" />
|
||||||
|
<!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<title>Testform</title>
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
|
<script>const ICON_PATHS = {
|
||||||
|
cameraofficon: "{{ url_for('static', filename='icons/camera-off-icon.png') }}",
|
||||||
|
cameraicon: "{{ url_for('static', filename='icons/camera-icon.png') }}",
|
||||||
|
stopicon: "{{ url_for('static', filename='icons/stop-icon.png') }}",
|
||||||
|
recordicon: "{{ url_for('static', filename='icons/record-icon.png') }}"
|
||||||
|
};</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/1017028141?badge=0&autopause=0&player_id=0&app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="0020-simple"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
|
||||||
|
|
||||||
|
<form class="formlayout" id="question_form" action="{{ url_for('sendpage') }}" method="post">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="likertcontainer">
|
||||||
|
<div class="likert" style="--likert-rows: 7">
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input class="inputs" name="test1" type="radio" id="test1" value="1" required /><span> Option 1
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input class="inputs" name="test1" type="radio" id="test1" value="1" required /><span> Option 2
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input class="inputs" name="test1" type="radio" id="test1" value="1" required /><span> Option 3
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input class="inputs" name="test1" type="radio" id="test1" value="1" required /><span> Option 4
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input class="inputs" name="test1" type="radio" id="test1" value="1" required /><span> Option 5
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input class="inputs" name="test1" type="radio" id="test1" value="1" required /><span> Option 6
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input class="inputs" name="test1" type="radio" id="test1" value="1" required /><span> Option 7
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="normal-likert-container" style="--likert-rows: 7">
|
||||||
|
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="test1" type="radio" id="test1" value="1" required /><span> Option 1
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="test1" type="radio" id="test1" value="1" required /><span> Option 2
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="test1" type="radio" id="test1" value="1" required /><span> Option 3
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="test1" type="radio" id="test1" value="1" required /><span> Option 4
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="test1" type="radio" id="test1" value="1" required /><span> Option 5
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="test1" type="radio" id="test1" value="1" required /><span> Option 6
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<label class="likertlabel">
|
||||||
|
<input class="likertinput" name="test1" type="radio" id="test1" value="1" required /><span> Option 7
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="textarea-container">
|
||||||
|
<label class="textarea-label">
|
||||||
|
<textarea class="inputs" id="text" name="text" rows="6" cols="60" maxlength="200"></textarea>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="centertext">
|
||||||
|
<button type="button" class="videocontrols" id="buttonCamera" onclick="cameraButton()">
|
||||||
|
<img id="buttonCameraIcon" src="{{ url_for('static', filename='icons/camera-icon.png')}}"
|
||||||
|
alt="Camera Icon">
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="button" class="videocontrols" id="buttonRecord" style="display:none"
|
||||||
|
onclick="recordButton()">
|
||||||
|
<img id="buttonRecordIcon" src="{{ url_for('static', filename='icons/record-icon.png')}}"
|
||||||
|
alt="Camera Icon">
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" class="videocontrols" id="buttonDelete" style="display:none" disabled
|
||||||
|
onclick="deleteButton()">
|
||||||
|
<img id="buttonDeleteIcon" src="{{ url_for('static', filename='icons/trash-icon.png')}}"
|
||||||
|
alt="Delete Icon" class="buttondisable">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:15px"></div>
|
||||||
|
<div id="videoContainer" style="display:none" class="video-container">
|
||||||
|
<video autoplay muted playsinline id="videoDisplay"></video>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='videoscript.js')}}">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<input class="inputs" id="submitbutton" type="submit" value="submit" />
|
||||||
|
<!-- TODO maybe I want to use this instead: <button id="submitbutton" type="submit">Submit</button> -->
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
34
slaeforms/templates/task3.html
Normal file
34
slaeforms/templates/task3.html
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}" />
|
||||||
|
<!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<title>Task 3 Videos</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="double_video_container">
|
||||||
|
<div class="dv_half">
|
||||||
|
<div class="iframe-container">
|
||||||
|
<video controls>
|
||||||
|
<source src="{{ url_for('static', filename='videos/0009-intro-inflected.mp4') }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dv_half">
|
||||||
|
<div class="iframe-container">
|
||||||
|
<video controls>
|
||||||
|
<source src="{{ url_for('static', filename='videos/0009-variation-inflected.mp4') }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="spacer" aria-hidden="true" style="height:30px"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
|
||||||
<title>Test Page 0 - Nothing</title>
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<p>This is just a test page for the single page option of the json configuration, but without something to submit</p>
|
|
||||||
<form action="http://localhost:5000/send_json" method="post">
|
|
||||||
<input type="hidden" name="submittedString" value="Hello, backend!">
|
|
||||||
<p><input id="submitbutton" type = "submit" value = "submit";/></p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
|
||||||
<title>Test Page 1 - Datenschutzerklaerung</title>
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<p>This is just a test page for the single page option of the json configuration</p>
|
|
||||||
<form action="http://localhost:5000/send_json" method="post">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id="accepted"
|
|
||||||
name="accepted"
|
|
||||||
value="checked" />
|
|
||||||
<label for="accepted">Akzeptieren sie die Datenschutzerklaerung</label>
|
|
||||||
<p><input id="submitbutton" type = "submit" value = "submit";/></p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,32 +1,74 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css')}}"" /> <!-- styles.css {{ url_for('static', filename='styles.css')}}-->
|
||||||
|
<link rel=" shortcut icon" href="{{ url_for('static', filename='icons/favicon.ico') }}">
|
||||||
<title>DGS Avatar Study</title>
|
<title>DGS Avatar Study</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>Hello! Thank you for participating in our study!</h2>
|
<h2>SLAEFORMS Gebärdensprachavatar Studie</h2>
|
||||||
|
|
||||||
<div class="textblock">
|
<div class="textblock">
|
||||||
<p>This is a placeholder EULA and Terms and Condition Text, this should obviously be replaced with some real Text later.
|
|
||||||
For now, be aware that this is a prototype for a sign language avatar study.
|
<p>
|
||||||
The Data that you input in this form, will be saved on our servers, but in an annonimized ways, so we can not infer who sent this data.
|
In dieser Studie geht es um die Entwicklung von Gebärdensprachavataren, also animierte 3D-Avatare, die
|
||||||
The Video recordings pose a special case. Any videos that are recorded, will be reviewed by sign language experts in our team,
|
Gebärdensprache sprechen sollen.
|
||||||
the meaning will be transcribed in text form, then the video will be deleted.
|
|
||||||
If you have further questions, please send an email to testemail@notarealemail.deee
|
</p>
|
||||||
|
<p>
|
||||||
|
Bitte beachten Sie, dass diese Avatare noch in einer frühen Entwicklungsphase und noch nicht für den
|
||||||
|
Gebrauch in der echten Welt geeignet sind. In dieser Studie geht es darum, einzelne Aspekte der Avatare
|
||||||
|
und neue technologische Ansätze zu testen. Dementsprechend haben die Avatare noch viele offensichtliche
|
||||||
|
Schwächen, wie zum Beispiel, dass bisher nur die Arme und der Oberkörper, aber nicht das Gesicht
|
||||||
|
animiert ist.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Diese Studie richtet sich an Menschen, die Gebärdensprache beherrschen, insbesondere gehörlose Menschen.
|
||||||
|
Nehmen Sie bitte nur Teil, wenn Sie (Deutsche) Gebärdensprache beherrschen.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Während der Studie werden sie sich Videos anschauen, diese bewerten und Feedback dazu geben können.
|
||||||
|
Verwenden Sie deshalb bitte, wenn möglich ein Gerät mit einem großen Bildschirm (Laptop, PC, Tablet) für
|
||||||
|
Ihre Teilnahme, damit Sie die Videos in ausreichender Größe sehen können.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Sie haben während der Studie die Möglichkeit (optional) Videofeedback zu geben, dazu brauchen sie eine
|
||||||
|
Webcam. Die Videos werden nicht veröffentlicht und nur Übersetzern zur Auswertung der Studienergebnisse
|
||||||
|
gezeigt.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Für jeden Teil der Studie gibt es ein Erklärvideo, das die Fragestellung und die Antwortmöglichkeiten in
|
||||||
|
Gebärdensprache erklärt. Falls Sie das Video während der Studie nochmal sehen möchten, können Sie es
|
||||||
|
über den „Info“-Knopf auf der rechten Seite aufrufen.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Die Teilnahme an dieser Studie ist komplett freiwillig, Sie können die Studie zu jedem Zeitpunkt
|
||||||
|
abbrechen, indem Sie die Seite einfach schließen. Sie können außerdem die Löschung aller Daten bei uns
|
||||||
|
beantragen: avatarstudy@proton.me
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Ich, bestätige, dass ich die „Information betroffener Personen zur Verarbeitung personenbezogener Daten“
|
||||||
|
erhalten habe.
|
||||||
|
Ich willige hiermit ein, dass das DFKI Daten aus wissenschaftlichen Experimenten im Zusammenhang mit
|
||||||
|
dieser Studie für die Darstellung von Forschungsergebnissen im Bereich des Affective Computing verwendet
|
||||||
|
werden.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Mir ist bekannt, dass ich das Recht habe, meine Einwilligung jederzeit zu widerrufen. Durch den Widerruf
|
||||||
|
der Einwilligung wird die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten
|
||||||
|
Verarbeitung nicht berührt. Ein Widerruf kann per Email an avatarstudy@proton.me geschickt werden.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<form class="dsgvoform" action="http://localhost:5000/start" method="post">
|
<form class="dsgvoform" action="{{ url_for('startpage') }}" method="post">
|
||||||
<label for="terms-and-conditions">
|
|
||||||
<input class="inline" id="terms-and-conditions" type="checkbox" required name="terms-and-conditions" /> I accept the +terms and conditions
|
|
||||||
</label>
|
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<input id="submitbutton" type="submit" value="submit" />
|
<input id="submitbutton" type="submit" value="submit" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,37 +1,325 @@
|
|||||||
{
|
{
|
||||||
"Block 1":{
|
|
||||||
"type": "SinglePage",
|
|
||||||
"template": "startpage.html"
|
|
||||||
},
|
|
||||||
"Block 2": {
|
"Block 2": {
|
||||||
"type": "TaskTemplate",
|
"type": "TaskTemplate",
|
||||||
"tempalte": "tempaltetest1.html",
|
"tempalte": "standard_template.html",
|
||||||
"name" : "Block2Responses",
|
"stimuli": {
|
||||||
"databasetable": {
|
"type": "single_video",
|
||||||
"question_title" : {
|
"order": "random",
|
||||||
"type":"likert"
|
"list": {
|
||||||
|
"video_1": "https://www.youtube-nocookie.com/embed/iI2bjpgLgu0?si=pWWwitq8Tl9zAs04",
|
||||||
|
"video_2": "https://www.youtube-nocookie.com/embed/R_LNEJiShRM?si=vm5mj-xs04nfijkf",
|
||||||
|
"video_3": "https://www.youtube-nocookie.com/embed/DJnHVnT2YEk?si=e6qe7nrHaRYJ3NQe",
|
||||||
|
"video_4": "https://www.youtube-nocookie.com/embed/6BTZn7tqSzk?si=jQH8RHGMIP9ARsT5",
|
||||||
|
"video_5": "https://www.youtube-nocookie.com/embed/bCRqmhWjuCk?si=iM2dwOSTosLq08Pr",
|
||||||
|
"video_6": "https://www.youtube-nocookie.com/embed/hgE2k8y9-qc?si=kR2rshmVcb9P70r0"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"question1": {
|
||||||
|
"type": "likert",
|
||||||
|
"name": "likertscale",
|
||||||
|
"text": "Wie würden sie dieses Video bewerten?",
|
||||||
|
"required": "true",
|
||||||
|
"points": {
|
||||||
|
"p1": {
|
||||||
|
"value": "1",
|
||||||
|
"text": "Ich finde es gar nicht gut 🙁👎"
|
||||||
|
},
|
||||||
|
"p2": {
|
||||||
|
"value": "2",
|
||||||
|
"text": "Ich finde es nicht gut 👎"
|
||||||
|
},
|
||||||
|
"p3": {
|
||||||
|
"value": "3",
|
||||||
|
"text": "Ich finde es weder gut noch schlecht"
|
||||||
|
},
|
||||||
|
"p4": {
|
||||||
|
"value": "4",
|
||||||
|
"text": "Ich finde es gut 👍"
|
||||||
|
},
|
||||||
|
"p5": {
|
||||||
|
"value": "5",
|
||||||
|
"text": "Ich finde es sehr gut 😊👍"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"question2": {
|
||||||
|
"type": "textinput",
|
||||||
|
"name": "text_feedback",
|
||||||
|
"text": "Hier können sie uns Feedback geben",
|
||||||
|
"required": "false",
|
||||||
|
"size": "250"
|
||||||
|
},
|
||||||
"question3": {
|
"question3": {
|
||||||
"type": "single",
|
"type": "videoinput",
|
||||||
"video1": "https://www.youtube-nocookie.com/embed/XTMIomsXxKM?si=r2zB6OKERH6Jdpi6",
|
"text": "Hier können sie per Video Feedback geben",
|
||||||
"scales": {
|
"name": "video_feedback",
|
||||||
"block1":{
|
"required": "false"
|
||||||
"type": "likert",
|
}
|
||||||
"numberofpoints": "3",
|
},
|
||||||
|
"infovideo": {
|
||||||
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden.\\n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt.\\n Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database_table": {
|
||||||
|
"table_name": "single_video_responses",
|
||||||
|
"fields": {
|
||||||
|
"likertscale": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": "false"
|
||||||
|
},
|
||||||
|
"text_feedback": {
|
||||||
|
"type": "string",
|
||||||
|
"size": "250",
|
||||||
|
"nullable": "true"
|
||||||
|
},
|
||||||
|
"video_upload": {
|
||||||
|
"type": "string",
|
||||||
|
"size": "100",
|
||||||
|
"nullable": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Block 1": {
|
||||||
|
"type": "TaskTemplate",
|
||||||
|
"tempalte": "standard_template.html",
|
||||||
|
"stimuli": {
|
||||||
|
"type": "empty",
|
||||||
|
"list": {
|
||||||
|
"empty_stimulus": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"question1_alter": {
|
||||||
|
"type": "numberinput",
|
||||||
|
"name": "alter",
|
||||||
|
"text": "Alter:",
|
||||||
|
"required": "true",
|
||||||
|
"min": "1",
|
||||||
|
"max": "120"
|
||||||
|
},
|
||||||
|
"question2_geschlecht": {
|
||||||
|
"type": "dropdowninput",
|
||||||
|
"name": "geschlecht",
|
||||||
|
"text": "Geschlecht:",
|
||||||
|
"required": "true",
|
||||||
|
"defaulttext": "",
|
||||||
"points": {
|
"points": {
|
||||||
"point1": "left",
|
"männlich": {
|
||||||
"point2": "none",
|
"value": "Männlich",
|
||||||
"point3": "right"
|
"text": "Männlich"
|
||||||
|
},
|
||||||
|
"weiblich": {
|
||||||
|
"value": "Weiblich",
|
||||||
|
"text": "Weiblich"
|
||||||
|
},
|
||||||
|
"divers": {
|
||||||
|
"value": "Divers",
|
||||||
|
"text": "Divers"
|
||||||
|
},
|
||||||
|
"keine_angabe": {
|
||||||
|
"value": "keine_angabe",
|
||||||
|
"text": "Keine Angabe"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"block2":{
|
"question3_hoerstatus": {
|
||||||
|
"type": "dropdowninput",
|
||||||
|
"name": "hoerstatus",
|
||||||
|
"text": "Hörstatus:",
|
||||||
|
"required": "true",
|
||||||
|
"defaulttext": "",
|
||||||
|
"points": {
|
||||||
|
"hörend": {
|
||||||
|
"value": "Hörend",
|
||||||
|
"text": "Hörend"
|
||||||
|
},
|
||||||
|
"schwerhörig": {
|
||||||
|
"value": "Schwerhörig",
|
||||||
|
"text": "Schwerhörig"
|
||||||
|
},
|
||||||
|
"gehörlos": {
|
||||||
|
"value": "Gehörlos",
|
||||||
|
"text": "Gehörlos"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question4_bevorzugte_kommunikation": {
|
||||||
|
"type": "dropdowninput",
|
||||||
|
"name": "bevorzugte_kommunikation",
|
||||||
|
"text": "Bevorzugte Kommunikationsform:",
|
||||||
|
"required": "true",
|
||||||
|
"defaulttext": "",
|
||||||
|
"points": {
|
||||||
|
"gesprochen": {
|
||||||
|
"value": "Gesprochene Sprache",
|
||||||
|
"text": "Gesprochene Sprache"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"value": "Text",
|
||||||
|
"text": "Text"
|
||||||
|
},
|
||||||
|
"gebärdensprache": {
|
||||||
|
"value": "Gebärdensprache",
|
||||||
|
"text": "Gebärdensprache"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question5_gebeardenzeitraum": {
|
||||||
|
"type": "numberinput",
|
||||||
|
"name": "gebärdenzeitraum",
|
||||||
|
"text": "Wie viele Jahre verwenden sie schon Gebärdensprache:",
|
||||||
|
"required": "true",
|
||||||
|
"min": "0",
|
||||||
|
"max": "100",
|
||||||
|
"step": "0.5"
|
||||||
|
},
|
||||||
|
"question6_sprachkompetenz": {
|
||||||
|
"type": "numberinput",
|
||||||
|
"name": "gebärdensprachkompetenz",
|
||||||
|
"text": "Wie schätzen sie ihre Gebärdensprachkompetenz ein (1-10):",
|
||||||
|
"required": "true",
|
||||||
|
"min": "1",
|
||||||
|
"max": "10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"infovideo": {
|
||||||
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. \n Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database_table": {
|
||||||
|
"table_name": "demographic_data",
|
||||||
|
"fields": {
|
||||||
|
"alter": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": "false"
|
||||||
|
},
|
||||||
|
"geschlecht": {
|
||||||
|
"type": "string",
|
||||||
|
"size": "14",
|
||||||
|
"nullable": "false"
|
||||||
|
},
|
||||||
|
"hoerstatus": {
|
||||||
|
"type": "string",
|
||||||
|
"size": "14",
|
||||||
|
"nullable": "false"
|
||||||
|
},
|
||||||
|
"bevorzugte_kommunikation": {
|
||||||
|
"type": "string",
|
||||||
|
"size": "22",
|
||||||
|
"nullable": "false"
|
||||||
|
},
|
||||||
|
"gebärdenzeitraum": {
|
||||||
|
"type": "float",
|
||||||
|
"nullable": "false"
|
||||||
|
},
|
||||||
|
"gebärdensprachkompetenz": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Block 3": {
|
||||||
|
"type": "TaskTemplate",
|
||||||
|
"tempalte": "standard_template.html",
|
||||||
|
"stimuli": {
|
||||||
|
"type": "double_video",
|
||||||
|
"list_1": {
|
||||||
|
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522",
|
||||||
|
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-"
|
||||||
|
},
|
||||||
|
"list_2": {
|
||||||
|
"video_2": "https://www.youtube-nocookie.com/embed/g9KA72jN5SM?si=O7dfqTXdFCCAScJ-",
|
||||||
|
"video_1": "https://www.youtube-nocookie.com/embed/IqGVT1q1PtM?si=kel7ZWEQl3h-h522"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"question1": {
|
||||||
|
"type": "likert",
|
||||||
|
"name": "likertscale",
|
||||||
|
"text": "Welches Video gefällt ihnen besser?",
|
||||||
|
"required": "true",
|
||||||
|
"points": {
|
||||||
|
"p1": {
|
||||||
|
"value": "1",
|
||||||
|
"text": "Ich finde das linke Video besser"
|
||||||
|
},
|
||||||
|
"p2": {
|
||||||
|
"value": "2",
|
||||||
|
"text": "Ich finde beide Videos gleich gut"
|
||||||
|
},
|
||||||
|
"p3": {
|
||||||
|
"value": "3",
|
||||||
|
"text": "Ich finde das rechte Video besser"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"infovideo": {
|
||||||
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database_table": {
|
||||||
|
"table_name": "double_video_responses",
|
||||||
|
"fields": {
|
||||||
|
"likertscale": {
|
||||||
|
"type": "integer",
|
||||||
|
"nullable": "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Block 4": {
|
||||||
|
"type": "TaskTemplate",
|
||||||
|
"tempalte": "standard_template.html",
|
||||||
|
"stimuli": {
|
||||||
|
"type": "empty",
|
||||||
|
"list": {
|
||||||
|
"empty_stimulus": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"question1": {
|
||||||
"type": "textinput",
|
"type": "textinput",
|
||||||
"length": "200"
|
"name": "formfeedback",
|
||||||
|
"text": "Das war der Prototyp für dieses Studientool. Über Feedback würde ich mich freuen. Entweder hier oder per Email unter: avatarstudy@proton.me",
|
||||||
|
"required": "false",
|
||||||
|
"size": "1000"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"block3":{
|
"infovideo": {
|
||||||
"type": "video"
|
"videourl": "https://www.youtube-nocookie.com/embed/F_w50c5Us3Y?si=-H07MmQ4lYOC2Bwh",
|
||||||
|
"infotext": "Hier wird in Zukunft ein Erklärtext stehen, in dem die Fragestellungen erklärt werden. Dazu werden alle Fragen der Seite einzeln durchgegangen und einfach erklärt. Zum Beispiel wird hier erklärt, dass man um Feedback zu geben, ein Video aufnehmen kann. Dazu drückt man auf den Knopf mit dem Videokamera Symbol. Danach muss man oben links am Browser bestätigen, dass der Browser auf die Kamera zugreifen darf.",
|
||||||
|
"configuration": {
|
||||||
|
"embed": "yt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database_table": {
|
||||||
|
"table_name": "feedback_responses",
|
||||||
|
"fields": {
|
||||||
|
"formfeedback": {
|
||||||
|
"type": "string",
|
||||||
|
"size": "1000",
|
||||||
|
"nullable": "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1080
slaeforms/userstudy1-vimeo.json
Normal file
1080
slaeforms/userstudy1-vimeo.json
Normal file
File diff suppressed because it is too large
Load Diff
1089
slaeforms/userstudy1.json
Normal file
1089
slaeforms/userstudy1.json
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user