Merge branch 'data_migrations' into odevzdavatko
This commit is contained in:
commit
b48d400543
54 changed files with 10996 additions and 182 deletions
8
Makefile
8
Makefile
|
@ -34,6 +34,8 @@ install_web: venv_check
|
||||||
pip install --upgrade setuptools
|
pip install --upgrade setuptools
|
||||||
# Instalace závislostí webu
|
# Instalace závislostí webu
|
||||||
pip install -r requirements.txt --upgrade
|
pip install -r requirements.txt --upgrade
|
||||||
|
# Po vygenerování testdat spusť ./manage.py loaddata sitetree_new.json, ať máš menu
|
||||||
|
# Pro synchronizaci flatpages spusť make sync_prod_flatpages
|
||||||
|
|
||||||
install_venv:
|
install_venv:
|
||||||
${VENV} ${VENV_PATH}
|
${VENV} ${VENV_PATH}
|
||||||
|
@ -139,3 +141,9 @@ sync_local_db:
|
||||||
|
|
||||||
# Sync database and media. See above lines
|
# Sync database and media. See above lines
|
||||||
sync_local: sync_local_media sync_local_db
|
sync_local: sync_local_media sync_local_db
|
||||||
|
|
||||||
|
# Push local compiled Vue to gimli test site
|
||||||
|
push_compiled_vue_to_test:
|
||||||
|
scp vue_frontend/webpack-stats.json mam-web@gimli:/akce/mam/www/mamweb-test/vue_frontend/
|
||||||
|
rsync -ave ssh seminar/static/seminar/vue mam-web@gimli:/akce/mam/www/mamweb-test/seminar/static/seminar/
|
||||||
|
ssh mam-web@gimli.ms.mff.cuni.cz 'cd /akce/mam/www/mamweb-test/ && . env/bin/activate && ./manage.py collectstatic --noinput'
|
||||||
|
|
File diff suppressed because one or more lines are too long
10
mamweb/routers.py
Normal file
10
mamweb/routers.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from rest_framework import routers
|
||||||
|
from seminar import viewsets as vs
|
||||||
|
|
||||||
|
router = routers.DefaultRouter()
|
||||||
|
|
||||||
|
router.register(r'ulohavzoraknode', vs.UlohaVzorakNodeViewSet,basename='ulohavzoraknode')
|
||||||
|
router.register(r'text', vs.TextViewSet)
|
||||||
|
router.register(r'textnode', vs.TextNodeViewSet)
|
||||||
|
router.register(r'castnode', vs.CastNodeViewSet)
|
||||||
|
|
|
@ -120,6 +120,10 @@ INSTALLED_APPS = (
|
||||||
'imagekit',
|
'imagekit',
|
||||||
|
|
||||||
'polymorphic',
|
'polymorphic',
|
||||||
|
|
||||||
|
'webpack_loader',
|
||||||
|
'rest_framework',
|
||||||
|
'rest_framework.authtoken',
|
||||||
|
|
||||||
# MaMweb
|
# MaMweb
|
||||||
'mamweb',
|
'mamweb',
|
||||||
|
@ -184,6 +188,27 @@ CKEDITOR_CONFIGS = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Webpack loader
|
||||||
|
VUE_FRONTEND_DIR = os.path.join(BASE_DIR, 'vue_frontend')
|
||||||
|
|
||||||
|
WEBPACK_LOADER = {
|
||||||
|
'DEFAULT': {
|
||||||
|
'CACHE': False,
|
||||||
|
'BUNDLE_DIR_NAME': 'vue/', # must end with slash
|
||||||
|
'STATS_FILE': os.path.join(VUE_FRONTEND_DIR, 'webpack-stats.json'),
|
||||||
|
'POLL_INTERVAL': 0.1,
|
||||||
|
'TIMEOUT': None,
|
||||||
|
'IGNORE': [r'.+\.hot-update.js', r'.+\.map']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Dajngo REST Framework
|
||||||
|
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
|
||||||
|
'PAGE_SIZE': 100
|
||||||
|
}
|
||||||
|
|
||||||
# Comments
|
# Comments
|
||||||
|
|
||||||
|
@ -270,6 +295,9 @@ LOGGING = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Permissions for uploads
|
||||||
|
FILE_UPLOAD_PERMISSIONS = 0o0644
|
||||||
|
|
||||||
# MaM specific
|
# MaM specific
|
||||||
|
|
||||||
SEMINAR_RESENI_DIR = os.path.join('reseni')
|
SEMINAR_RESENI_DIR = os.path.join('reseni')
|
||||||
|
|
38
mamweb/static/css/mamweb-dev.css
Normal file
38
mamweb/static/css/mamweb-dev.css
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
.pink {
|
||||||
|
background-color: #ffc0cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.borderized {
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tnmenu {
|
||||||
|
float: right;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.parent {
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.children {
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.node_type {
|
||||||
|
background-color: #d4d4d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-tn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*test*/
|
||||||
|
h1 {
|
||||||
|
color: chartreuse;
|
||||||
|
}
|
|
@ -759,17 +759,26 @@ div.odpocet {
|
||||||
|
|
||||||
/*stránka organizátorů*/
|
/*stránka organizátorů*/
|
||||||
|
|
||||||
div.seznam_orgu {
|
div.seznam_orgu, div.rozcestnik_temat {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.org_pole, div.rocnik_pole {
|
div.org_pole, div.rocnik_pole, div.tema_pole {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 30%;
|
width: 30%;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.tema_pole {
|
||||||
|
display: inline-block;
|
||||||
|
width: 40%;
|
||||||
|
min-width: 350px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
div.cislo_pole {
|
div.cislo_pole {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 15%;
|
width: 15%;
|
||||||
|
@ -812,6 +821,11 @@ div.org_email {
|
||||||
height: 205px;
|
height: 205px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tema-rozcestnik.flip-card {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
/* This container is needed to position the front and back side */
|
/* This container is needed to position the front and back side */
|
||||||
.flip-card-inner {
|
.flip-card-inner {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -835,7 +849,8 @@ div.org_email {
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.flip-card-foto img {
|
|
||||||
|
div.flip-card-foto, div.flip-card-foto img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
<title>{% block title %}{% block nadpis1a %}{% endblock %} – Korespondenční seminář M&M{% endblock title %}</title>
|
<title>{% block title %}{% block nadpis1a %}{% endblock %} – Korespondenční seminář M&M{% endblock title %}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon">
|
<link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon">
|
||||||
{% render_block "css" %}
|
{% render_block css %}
|
||||||
|
{% block custom_css %}{% endblock %}
|
||||||
<link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
|
<link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
|
<link href="{% static 'css/bootstrap.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/mamweb.css' %}" rel="stylesheet">
|
<link href="{% static 'css/mamweb.css' %}" rel="stylesheet">
|
||||||
|
|
|
@ -6,6 +6,8 @@ from django.views.generic.base import TemplateView
|
||||||
from django import views
|
from django import views
|
||||||
from django.urls import path # As per docs.
|
from django.urls import path # As per docs.
|
||||||
|
|
||||||
|
from .routers import router
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
||||||
# Admin a nastroje
|
# Admin a nastroje
|
||||||
|
@ -25,6 +27,9 @@ urlpatterns = [
|
||||||
path('comments_dj/', include('django_comments.urls')),
|
path('comments_dj/', include('django_comments.urls')),
|
||||||
path('comments_fl/', include('fluent_comments.urls')),
|
path('comments_fl/', include('fluent_comments.urls')),
|
||||||
|
|
||||||
|
# REST API
|
||||||
|
path('api/', include(router.urls)),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# This is only needed when using runserver.
|
# This is only needed when using runserver.
|
||||||
|
|
|
@ -28,6 +28,9 @@ django-imagekit
|
||||||
django-polymorphic
|
django-polymorphic
|
||||||
django-sitetree
|
django-sitetree
|
||||||
django_reverse_admin
|
django_reverse_admin
|
||||||
|
django-rest-framework
|
||||||
|
django-webpack-loader
|
||||||
|
django-rest-polymorphic
|
||||||
|
|
||||||
# Comments
|
# Comments
|
||||||
akismet==1.0.1
|
akismet==1.0.1
|
||||||
|
|
1
seminar/.~lock.profile_vysledkovka.txt#
Normal file
1
seminar/.~lock.profile_vysledkovka.txt#
Normal file
|
@ -0,0 +1 @@
|
||||||
|
,anet,erebus,25.03.2020 22:21,file:///home/anet/.config/libreoffice/4;
|
|
@ -107,6 +107,8 @@ class TreeNodeAdmin(PolymorphicParentModelAdmin):
|
||||||
m.PohadkaNode,
|
m.PohadkaNode,
|
||||||
m.UlohaVzorakNode,
|
m.UlohaVzorakNode,
|
||||||
m.TextNode,
|
m.TextNode,
|
||||||
|
m.CastNode,
|
||||||
|
m.OrgTextNode,
|
||||||
]
|
]
|
||||||
|
|
||||||
actions = ['aktualizuj_nazvy']
|
actions = ['aktualizuj_nazvy']
|
||||||
|
@ -160,6 +162,17 @@ class TextNodeAdmin(PolymorphicChildModelAdmin):
|
||||||
base_model = m.TextNode
|
base_model = m.TextNode
|
||||||
show_in_index = True
|
show_in_index = True
|
||||||
|
|
||||||
|
@admin.register(m.CastNode)
|
||||||
|
class TextNodeAdmin(PolymorphicChildModelAdmin):
|
||||||
|
base_model = m.CastNode
|
||||||
|
show_in_index = True
|
||||||
|
fields = ('nadpis',)
|
||||||
|
|
||||||
|
@admin.register(m.OrgTextNode)
|
||||||
|
class TextNodeAdmin(PolymorphicChildModelAdmin):
|
||||||
|
base_model = m.OrgTextNode
|
||||||
|
show_in_index = True
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(m.Nastaveni, SingletonModelAdmin)
|
admin.site.register(m.Nastaveni, SingletonModelAdmin)
|
||||||
admin.site.register(m.Novinky)
|
admin.site.register(m.Novinky)
|
||||||
|
|
|
@ -277,3 +277,8 @@ ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni,
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class NahrajObrazekKTreeNoduForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = m.Obrazek
|
||||||
|
fields = ('na_web',)
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ from reversion import revisions as reversion
|
||||||
from seminar.utils import roman, FirstTagParser # Pro získání úryvku z TextNode
|
from seminar.utils import roman, FirstTagParser # Pro získání úryvku z TextNode
|
||||||
|
|
||||||
from unidecode import unidecode # Používám pro získání ID odkazu (ještě je to někde po někom zakomentované)
|
from unidecode import unidecode # Používám pro získání ID odkazu (ještě je to někde po někom zakomentované)
|
||||||
from seminar.treelib import safe_pred
|
|
||||||
|
|
||||||
from polymorphic.models import PolymorphicModel
|
from polymorphic.models import PolymorphicModel
|
||||||
|
|
||||||
|
@ -744,11 +743,20 @@ class Problem(SeminarModelBase,PolymorphicModel):
|
||||||
return '<Není zadaný>'
|
return '<Není zadaný>'
|
||||||
|
|
||||||
def verejne(self):
|
def verejne(self):
|
||||||
# FIXME: Tohle se liší podle typu problému, má se udělat polymorfně.
|
# aktuálně podle stavu problému
|
||||||
# Zatím je tu jen dummy fail-safe default: nic není veřejné.
|
# FIXME pro některé problémy možná chceme override
|
||||||
return False
|
# FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je.
|
||||||
# FIXME: Tohle je blbost
|
# Je to tak správně?
|
||||||
return (self.cislo_zadani and self.cislo_zadani.verejne())
|
stav_verejny = False
|
||||||
|
if self.stav == 'zadany' or self.stav == 'vyreseny':
|
||||||
|
stav_verejny = True
|
||||||
|
return stav_verejny
|
||||||
|
|
||||||
|
#cislo_verejne = False
|
||||||
|
#if (self.cislo_zadani and self.cislo_zadani.verejne()):
|
||||||
|
# cislo_verejne = True
|
||||||
|
|
||||||
|
#return (stav_verejny and cislo_verejne)
|
||||||
verejne.boolean = True
|
verejne.boolean = True
|
||||||
|
|
||||||
def verejne_url(self):
|
def verejne_url(self):
|
||||||
|
@ -844,9 +852,7 @@ class Text(SeminarModelBase):
|
||||||
tn.save()
|
tn.save()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
parser = FirstTagParser()
|
return str(self.na_web)[:20]
|
||||||
parser.feed(str(self.na_web))
|
|
||||||
return parser.firstTag
|
|
||||||
|
|
||||||
class Uloha(Problem):
|
class Uloha(Problem):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -1367,6 +1373,7 @@ class MezicisloNode(TreeNode):
|
||||||
|
|
||||||
# TODO: Využít TreeLib
|
# TODO: Využít TreeLib
|
||||||
def aktualizuj_nazev(self):
|
def aktualizuj_nazev(self):
|
||||||
|
from seminar.treelib import safe_pred
|
||||||
if safe_pred(self) is not None:
|
if safe_pred(self) is not None:
|
||||||
if (self.prev.get_real_instance_class() != CisloNode and
|
if (self.prev.get_real_instance_class() != CisloNode and
|
||||||
self.prev.get_real_instance_class() != MezicisloNode):
|
self.prev.get_real_instance_class() != MezicisloNode):
|
||||||
|
|
7
seminar/permissions.py
Normal file
7
seminar/permissions.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from rest_framework.permissions import BasePermission
|
||||||
|
|
||||||
|
class AllowWrite(BasePermission):
|
||||||
|
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return request.user.has_perm('auth.org')
|
||||||
|
|
BIN
seminar/static/images/tema-bez-obrazku.png
Normal file
BIN
seminar/static/images/tema-bez-obrazku.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 300 KiB |
18
seminar/static/seminar/treenode_editor.js
Normal file
18
seminar/static/seminar/treenode_editor.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
function showSelectedItemForm(sel,id){
|
||||||
|
var option;
|
||||||
|
var name;
|
||||||
|
var div;
|
||||||
|
Array.from(sel.options).forEach(function(option){
|
||||||
|
console.log(option);
|
||||||
|
name = 'pridat-'+option.value+'-'+id;
|
||||||
|
div = document.getElementById(name);
|
||||||
|
console.log(div);
|
||||||
|
div.style.display = 'none';
|
||||||
|
});
|
||||||
|
name = sel.options[sel.selectedIndex].value;
|
||||||
|
name = 'pridat-'+name+'-'+id;
|
||||||
|
div = document.getElementById(name);
|
||||||
|
console.log(div);
|
||||||
|
div.style.display = 'block';
|
||||||
|
|
||||||
|
}
|
97
seminar/templates/seminar/archiv/cislo-normal.html
Normal file
97
seminar/templates/seminar/archiv/cislo-normal.html
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
{% extends "seminar/archiv/base_cisla.html" %}
|
||||||
|
|
||||||
|
{# {% block content %}
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
{% block nadpis1a %}{% block nadpis1b %}
|
||||||
|
Číslo {{ cislo }}
|
||||||
|
{% endblock %}{% endblock %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{% if cislo.pdf %}
|
||||||
|
<p><a href='{{ cislo.pdf.url }}'>Číslo v pdf</a>
|
||||||
|
{% endif %}
|
||||||
|
<p><a href='{{ cislo.rocnik.verejne_url }}'>Ročník {{ cislo.rocnik }}</a>
|
||||||
|
|
||||||
|
{% if v_cisle_zadane %}
|
||||||
|
<h2>Zadané problémy</h2>
|
||||||
|
<ul>
|
||||||
|
{% for p in v_cisle_zadane %}
|
||||||
|
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
|
||||||
|
{% if user.is_staff or cislo.verejne %}
|
||||||
|
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if resene_problemy %}
|
||||||
|
<h2>Řešené problémy</h2>
|
||||||
|
<ul>
|
||||||
|
{% for p in resene_problemy %}
|
||||||
|
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}>
|
||||||
|
{% if user.is_staff or cislo.verejne %}
|
||||||
|
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<div class="mam-org-only">
|
||||||
|
<h2> Orgovské odkazy </h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="obalky.pdf">Obálky (PDF)</a></li>
|
||||||
|
<li><a href="tituly.tex">Tituly (TeX)</a></li>
|
||||||
|
<li><a href="vysledkovka.tex">Výsledkovka (TeX)</a></li>
|
||||||
|
<li><a href="obalkovani">Obálkování</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if cislo.verejna_vysledkovka %}
|
||||||
|
<h2>Výsledkovka</h2>
|
||||||
|
{% else %}
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<div class='mam-org-only'>
|
||||||
|
<h2>Výsledkovka (neveřejná)</h2>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if cislo.verejna_vysledkovka or user.is_staff %}
|
||||||
|
<table class='vysledkovka'>
|
||||||
|
<tr class='border-b'>
|
||||||
|
<th class='border-r'>#
|
||||||
|
<th class='border-r'>Jméno #}
|
||||||
|
{# problémy by měly být veřejné, když je veřejná výsledkovka #}
|
||||||
|
{# {% for p in problemy %}
|
||||||
|
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
<th class='border-r'>Za číslo</sup>
|
||||||
|
<th class='border-r'>Za ročník
|
||||||
|
<th class='border-r'>Odjakživa
|
||||||
|
{% for rv in radky_vysledkovky %}
|
||||||
|
<tr>
|
||||||
|
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %}
|
||||||
|
<th class='border-r'>
|
||||||
|
{% if rv.resitel.titul != "" %}
|
||||||
|
{{ rv.resitel.titul }}<sup>MM</sup>
|
||||||
|
{% endif %}
|
||||||
|
{{ rv.resitel.osoba.plne_jmeno }}
|
||||||
|
{% for b in rv.hlavni_problemy_body %}
|
||||||
|
<td class='border-r'>{{ b }}
|
||||||
|
{% endfor %}
|
||||||
|
<td class='border-r'>{{ rv.body_cislo }}
|
||||||
|
<td class='border-r'><b>{{ rv.body_rocnik }}</b>
|
||||||
|
<td class='border-r'>{{ rv.body_celkem_odjakziva }}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not cislo.verejna_vysledkovka and user.is_staff %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock content %} #}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load render_bundle from webpack_loader %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div>
|
<div>
|
||||||
|
@ -48,6 +49,14 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<script id="vuedata" type="application/json">{"treenode":{{cislo.cislonode.id}}}</script>
|
||||||
|
<div id="app">
|
||||||
|
<app></app>
|
||||||
|
</div>
|
||||||
|
{% render_bundle 'chunk-vendors' %}
|
||||||
|
{% render_bundle 'vue_app_01' %}
|
||||||
|
|
||||||
|
|
||||||
{% if cislo.verejna_vysledkovka %}
|
{% if cislo.verejna_vysledkovka %}
|
||||||
<h2>Výsledkovka</h2>
|
<h2>Výsledkovka</h2>
|
||||||
|
|
||||||
|
|
19
seminar/templates/seminar/archiv/problem_tema.html
Normal file
19
seminar/templates/seminar/archiv/problem_tema.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{% extends "seminar/archiv/problem.html" %}
|
||||||
|
|
||||||
|
{% block problem %}
|
||||||
|
<h1>
|
||||||
|
{% block nadpis1a %}{% block nadpis1b %}
|
||||||
|
{{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }}
|
||||||
|
{% endblock %}{% endblock %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<h2>Zadání</h2>
|
||||||
|
{{ problem.text_zadani |safe }}
|
||||||
|
{% if problem.text_reseni %}
|
||||||
|
<h2>Řešení</h2>
|
||||||
|
{{ problem.text_reseni |safe }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# TODO vysledkovka tematu #}
|
||||||
|
|
||||||
|
{% endblock %}
|
23
seminar/templates/seminar/archiv/problem_uloha.html
Normal file
23
seminar/templates/seminar/archiv/problem_uloha.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{% extends "seminar/archiv/problem.html" %}
|
||||||
|
|
||||||
|
{% block problem %}
|
||||||
|
<h1>
|
||||||
|
{% block nadpis1a %}{% block nadpis1b %}
|
||||||
|
{{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }} {{ problem.body_v_zavorce }}
|
||||||
|
{% endblock %}{% endblock %}
|
||||||
|
</h1>
|
||||||
|
{% if problem.cislo_zadani %}
|
||||||
|
<p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>.
|
||||||
|
{% endif %}
|
||||||
|
{% if problem.cislo_reseni %}
|
||||||
|
<p>Řešeno v čísle <a href='{{ problem.cislo_reseni.verejne_url }}'>{{ problem.cislo_reseni.kod }}</a>.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h2>Zadání</h2>
|
||||||
|
{{ problem.text_zadani |safe }}
|
||||||
|
{% if problem.text_reseni %}
|
||||||
|
<h2>Řešení</h2>
|
||||||
|
{{ problem.text_reseni |safe }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
23
seminar/templates/seminar/orphanage.html
Normal file
23
seminar/templates/seminar/orphanage.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{% extends "seminar/archiv/base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load sekizai_tags %}
|
||||||
|
|
||||||
|
{# toto z nejakeho duvodu nefunguje #}
|
||||||
|
{% addtoblock css %}
|
||||||
|
dfsdfs
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/mamweb-dev.css' %}" />
|
||||||
|
{% endaddtoblock "css" %}
|
||||||
|
|
||||||
|
{% block custom_css %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/mamweb-dev.css' %}" />
|
||||||
|
{% endblock custom_css %}
|
||||||
|
|
||||||
|
{% load comments %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<ul>
|
||||||
|
{% for obj in object_list %}
|
||||||
|
<li>{{obj}} (id {{obj.id}})</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock content %}
|
|
@ -1,14 +1,54 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
{% block nadpis1a %}{% block nadpis1b %}
|
||||||
|
Aktuální témata
|
||||||
|
{% endblock %}{% endblock %}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p>Témata jsou texty nejen z oblasti matematiky, fyziky a informatiky, které popisují nějaký
|
||||||
|
problém a jsou doprovázeny návodnými úlohami. Vaším úkolem je zamyslet se nad daným
|
||||||
|
problémem a sepsat vaše úvahy ve formě krátkého textu.</p>
|
||||||
|
|
||||||
|
<p><a href="/co-je-MaM/jak-resit/">Jak řešit téma?</a></p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="rozcestnik_temat">
|
||||||
|
|
||||||
{% for tematko in tematka %}
|
{% for tematko in tematka %}
|
||||||
<h1>{{tematko.nazev}}</h1>
|
|
||||||
<p>{{tematko.abstrakt}}</p>
|
{# karta témátka - zepředu ilustrační, zezadu abstrakt #}
|
||||||
<ul>
|
<div class="tema_pole">
|
||||||
{% for cislo in tematko.cisla %}
|
|
||||||
<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{cislo.0.1}}">{{cislo.0.0}}</a></li>
|
<h3>
|
||||||
<ul>
|
<a href='{{ rocnik.verejne_url }}'>Téma {{ tematko.nazev }}</a>
|
||||||
{% for odkaz in cislo.1 %}
|
</h3>
|
||||||
<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{odkaz.1}}">{{odkaz.0}}</a></li>
|
|
||||||
{% endfor %}
|
<div class="flip-card" id="tema-rozcestnik">
|
||||||
</ul>
|
|
||||||
{% endfor %}
|
<div class="flip-card-inner">
|
||||||
</ul>
|
<div class="flip-card-front">
|
||||||
|
<div class="flip-card-foto">
|
||||||
|
{% if tematko.obrazek %}
|
||||||
|
<img src="{{ tematko.obrazek.url }}" alt="{{ tematko.nazev }}">
|
||||||
|
{% else %} {# pokud témátko nemá fotku, zobrazuje se defaultní obrázek #}
|
||||||
|
{% load static %} <img src="{% static 'images/tema-bez-obrazku.png' %}" alt="{{ tematko.nazev }}">
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flip-card-back">
|
||||||
|
<p>{{ tematko.abstrakt }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{# konec karty témátka #}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load render_bundle from webpack_loader %}
|
||||||
|
|
||||||
{% load comments %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div id="app">
|
||||||
|
<app></app>
|
||||||
|
</div>
|
||||||
|
{% render_bundle 'chunk-vendors' %}
|
||||||
|
{% render_bundle 'vue_app_01' %}
|
||||||
|
|
||||||
{%with obj=tnldata depth=1 template_name="seminar/treenode_recursive.html" %}
|
|
||||||
{%include template_name%}
|
|
||||||
{%endwith%}
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
27
seminar/templates/seminar/treenode_add_stub.html
Normal file
27
seminar/templates/seminar/treenode_add_stub.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{% load treenodes %}
|
||||||
|
{% if kam_slug == "syn" %}
|
||||||
|
{% appendableChildren obj as dostupne_typy %}
|
||||||
|
{% else %}
|
||||||
|
{% appendableChildren obj.parent as dostupne_typy %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# ulohaZadani ulohaVzorak Reseni Cast Text #}
|
||||||
|
{% if dostupne_typy %}
|
||||||
|
<div class="pink">Přidat {{kam}}
|
||||||
|
<select name="pridat-typ-{{obj.node.id}}-{{kam_slug}}" onchange="showSelectedItemForm(this,'{{obj.node.id}}-{{kam_slug}}')">
|
||||||
|
{% for typ in dostupne_typy %}
|
||||||
|
<option value="{{typ.0}}">{{typ.1}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<div class="hidden-tn" id="pridat-castNode-{{obj.node.id}}-{{kam_slug}}">
|
||||||
|
Nadpis: <input name="pridat-cast-{{obj.node.id}}-{{kam_slug}}" type="text">
|
||||||
|
<button action="submit" formaction="{%url 'treenode_pridat' obj.node.id kam_slug%}">Přidat</button>
|
||||||
|
</div>
|
||||||
|
<div class="hidden-tn" id="pridat-textNode-{{obj.node.id}}-{{kam_slug}}"> Vytvořit</div>
|
||||||
|
<div class="hidden-tn" id="pridat-reseniNode-{{obj.node.id}}-{{kam_slug}}">Vytvořit, Tady bude autocomplete na reseniNode</div>
|
||||||
|
<div class="hidden-tn" id="pridat-ulohaZadaniNode-{{obj.node.id}}-{{kam_slug}}">Vytvořit zadání</div>
|
||||||
|
<div class="hidden-tn" id="pridat-ulohaVzorakNode-{{obj.node.id}}-{{kam_slug}}">Vytvořit vzorák k: Tady bude autocomplete na problémy k aktuálnímu kontextu</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}{# appendablebleChildren #}
|
18
seminar/templates/seminar/treenode_name.html
Normal file
18
seminar/templates/seminar/treenode_name.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{% load treenodes %}
|
||||||
|
{% if obj.node|isRocnik %}
|
||||||
|
<h{{depth}}> Ročník {{obj.node.rocnik}} </h{{depth}}>
|
||||||
|
{% elif obj.node|isCislo %}
|
||||||
|
<h{{depth}}> Číslo {{obj.node.cislo}} </h{{depth}}>
|
||||||
|
{% elif obj.node|isTemaVCisle %}
|
||||||
|
<h{{depth}}> Téma {{obj.node.tema.nazev}} </h{{depth}}>
|
||||||
|
{% elif obj.node|isUlohaZadani %}
|
||||||
|
<h{{depth}}>Úloha {{obj.node.uloha.kod_v_rocniku}} ({{obj.node.uloha.max_body}} b)</h{{depth}}>
|
||||||
|
{% elif obj.node|isUlohaVzorak %}
|
||||||
|
<h{{depth}}>Řešení: {{obj.node.uloha.kod_v_rocniku}}</h{{depth}}>
|
||||||
|
{% elif obj.node|isCast %}
|
||||||
|
<h{{depth}}> {{obj.node.nadpis}} </h{{depth}}>
|
||||||
|
{% elif obj.node|isText %}
|
||||||
|
{{obj.node.text.na_web}}
|
||||||
|
{% else %}
|
||||||
|
Objekt jiného typu {{obj.node}}
|
||||||
|
{% endif %}
|
|
@ -1,28 +1,55 @@
|
||||||
{% load treenodes %}
|
{% load treenodes %}
|
||||||
{# <b>{{depth}}</b> #}
|
{# <b>{{depth}}</b> #}
|
||||||
<div>
|
<div class="borderized parent">
|
||||||
{% if obj.node|isRocnik %}
|
<div class="node_type">
|
||||||
<h{{depth}}> Ročník {{obj.node.rocnik}} </h{{depth}}>
|
{{obj.node}}
|
||||||
{% elif obj.node|isCislo %}
|
{{obj.node.id}}
|
||||||
<h{{depth}}> Číslo {{obj.node.cislo}} </h{{depth}}>
|
{% if obj.node|deletable %}
|
||||||
{% elif obj.node|isTemaVCisle %}
|
<button type="submit" formaction="{%url 'treenode_smazat' obj.node.id%}">Smazat</button>
|
||||||
<h{{depth}}> Téma {{obj.node.tema.nazev}} </h{{depth}}>
|
{% endif %}
|
||||||
{% elif obj.node|isUlohaZadani %}
|
{% if obj.parent and obj.parent|editableSiblings %}
|
||||||
<h{{depth}}>Úloha {{obj.node.uloha.kod_v_rocniku}} ({{obj.node.uloha.max_body}} b)</h{{depth}}>
|
<button type="submit" formaction="{%url 'treenode_odvesitpryc' obj.node.id%}">Odvěsit pryč ze stromu {{obj.parent.node}}</button>
|
||||||
{% elif obj.node|isUlohaVzorak %}
|
{% endif %}
|
||||||
<h{{depth}}>Řešení: {{obj.node.uloha.kod_v_rocniku}}</h{{depth}}>
|
{% if obj|canPodvesitPred %}
|
||||||
{% elif obj.node|isText %}
|
<button type="submit" formaction="{%url 'treenode_podvesit' obj.node.id 'pred'%}">Podvěsit pod předchozí</button> - nejsou testovací data
|
||||||
{{obj.node.text.na_web}}
|
{% endif %}
|
||||||
{% else %}
|
{% if obj|canPodvesitZa %}
|
||||||
Objekt jiného typu {{obj.node}}
|
<button type="submit" formaction="{%url 'treenode_podvesit' obj.node.id 'za'%}">Podvěsit pod následující</button> - nejsou testovací data
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%if obj.children %}
|
|
||||||
<div>
|
|
||||||
{%for ch in obj.children %}
|
</div>
|
||||||
{%with obj=ch depth=depth|add:"1" template_name="seminar/treenode_recursive.html" %}
|
{% if False %}
|
||||||
{%include template_name%}
|
<div class="node_move">
|
||||||
{%endwith%}
|
FIXME: není zatím implementováno
|
||||||
{%endfor%}
|
<button>Zvyš úroveň nadpisu</button> - nejsou testovací data
|
||||||
</div>
|
</div>
|
||||||
{%endif%}
|
{% endif %}
|
||||||
|
{% include "seminar/treenode_name.html" %}
|
||||||
|
{%if obj.children %}
|
||||||
|
<div class="borderized children">
|
||||||
|
|
||||||
|
{% with kam="před" kam_slug="syn" %} {% include "seminar/treenode_add_stub.html" %} {% endwith %}
|
||||||
|
{%for ch in obj.children %}
|
||||||
|
|
||||||
|
{# ----------- Vypisujeme podstrom ----------#}
|
||||||
|
{%with obj=ch depth=depth|add:"1" %} {%include "seminar/treenode_recursive.html" %} {%endwith%}
|
||||||
|
{# ----------- Přidáváme mezi syny / za posledního -------- #}
|
||||||
|
{% if forloop.last %}
|
||||||
|
{% with kam="za" kam_slug="za" obj=ch %} {% include "seminar/treenode_add_stub.html" %} {% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with kam="mezi" obj=ch kam_slug="za" %} {% include "seminar/treenode_add_stub.html" %} {% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{# ----------- Prohazujeme sousedy ----------#}
|
||||||
|
<div class="pink">
|
||||||
|
{% if not forloop.last and ch|editableSiblings %}
|
||||||
|
<button type="submit" formaction="{%url 'treenode_prohodit' ch.node.id%}">Prohodit ^ a v</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{# ----------- Přidáváme prvního syna ----------#}
|
||||||
|
{% with kam="jako syna" kam_slug="syn" %} {% include "seminar/treenode_add_stub.html" %} {% endwith %}
|
||||||
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
|
|
7
seminar/templates/seminar/vuetest.html
Normal file
7
seminar/templates/seminar/vuetest.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{% load render_bundle from webpack_loader %}
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<app></app>
|
||||||
|
</div>
|
||||||
|
{% render_bundle 'chunk-vendors' %}
|
||||||
|
{% render_bundle 'vue_app_01' %}
|
|
@ -1,49 +1,243 @@
|
||||||
from django import template
|
from django import template
|
||||||
|
from enum import Enum
|
||||||
import seminar.models as m
|
import seminar.models as m
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def nodeType(value):
|
||||||
|
if isinstance(value,RocnikNode): return "Ročník"
|
||||||
|
if isinstance(value,CisloNode): return "Číslo"
|
||||||
|
if isinstance(value,CastNode): return "Část"
|
||||||
|
if isinstance(value,TextNode): return "Text"
|
||||||
|
if isinstance(value,TemaVCisleNode): return "Téma v čísle"
|
||||||
|
if isinstance(value,KonferaNode): return "Konfera"
|
||||||
|
if isinstance(value,ClanekNode): return "Článek"
|
||||||
|
if isinstance(value,UlohaVzorakNode): return "Vzorák"
|
||||||
|
if isinstance(value,UlohaZadaniNode): return "Zadání úlohy"
|
||||||
|
if isinstance(value,PohadkaNode): return "Pohádka"
|
||||||
|
|
||||||
|
### NASLEDUJICI FUNKCE SE POUZIVAJI VE views_all.py V SEKCI PRIPRAVJICI TNLData
|
||||||
|
### NEMAZAT, PRESUNOUT S TNLDaty NEKAM BOKEM
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isRocnik(value):
|
def isRocnik(value):
|
||||||
return isinstance(value, m.RocnikNode)
|
return isinstance(value, m.RocnikNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isCislo(value):
|
def isCislo(value):
|
||||||
return isinstance(value, m.CisloNode)
|
return isinstance(value, m.CisloNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isCast(value):
|
def isCast(value):
|
||||||
return isinstance(value, m.CastNode)
|
return isinstance(value, m.CastNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isText(value):
|
def isText(value):
|
||||||
return isinstance(value, m.TextNode)
|
return isinstance(value, m.TextNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isTemaVCisle(value):
|
def isTemaVCisle(value):
|
||||||
return isinstance(value, m.TemaVCisleNode)
|
return isinstance(value, m.TemaVCisleNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isKonfera(value):
|
def isKonfera(value):
|
||||||
return isinstance(value, m.KonferaNode)
|
return isinstance(value, m.KonferaNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isClanek(value):
|
def isClanek(value):
|
||||||
return isinstance(value, m.ClanekNode)
|
return isinstance(value, m.ClanekNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isUlohaVzorak(value):
|
def isUlohaVzorak(value):
|
||||||
return isinstance(value, m.UlohaVzorakNode)
|
return isinstance(value, m.UlohaVzorakNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isUlohaZadani(value):
|
def isUlohaZadani(value):
|
||||||
return isinstance(value, m.UlohaZadaniNode)
|
return isinstance(value, m.UlohaZadaniNode)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def isPohadka(value):
|
def isPohadka(value):
|
||||||
return isinstance(value, m.PohadkaNode)
|
return isinstance(value, m.PohadkaNode)
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def isReseni(value):
|
||||||
|
return False
|
||||||
|
# return isinstance(value, m.OtisteneReseniNode)
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def isOrgText(value):
|
||||||
|
return False
|
||||||
|
# return isinstance(value, m.OrgTextNode)
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
#@register.filter
|
#@register.filter
|
||||||
#def isOtisteneReseniNode(value):
|
#def podvesitelneNody(value):
|
||||||
# return isinstance(value, m.OtisteneReseniNode)
|
# if isText()
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def deletable(value):
|
||||||
|
if isTemaVCisle(value):
|
||||||
|
return True
|
||||||
|
if isOrgText(value):
|
||||||
|
return True
|
||||||
|
if isReseni(value):
|
||||||
|
return True
|
||||||
|
if isUlohaZadani(value):
|
||||||
|
return True
|
||||||
|
if isUlohaVzorak(value):
|
||||||
|
return True
|
||||||
|
if isCast(value):
|
||||||
|
return True
|
||||||
|
if isText(value):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def editableSiblings(value):
|
||||||
|
if isCast(value.node):
|
||||||
|
return True
|
||||||
|
if isText(value.node):
|
||||||
|
return True
|
||||||
|
if isReseni(value.node) and value.tema_in_path:
|
||||||
|
return True
|
||||||
|
if isUlohaZadani(value.node) and value.tema_in_path:
|
||||||
|
return True
|
||||||
|
if isUlohaVzorak(value.node) and value.tema_in_path:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def editableChildren(value):
|
||||||
|
if isRocnik(value.node):
|
||||||
|
return False
|
||||||
|
if isCislo(value.node):
|
||||||
|
return False
|
||||||
|
if isText(value.node):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def textOnlySubtree(value):
|
||||||
|
text_only = True
|
||||||
|
if isText(value.node):
|
||||||
|
return True
|
||||||
|
if not isCast(value.node):
|
||||||
|
return False
|
||||||
|
for ch in value.children:
|
||||||
|
if not textOnlySubtree(ch):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def canPodvesit(obj,new_parent):
|
||||||
|
if isCast(new_parent.node):
|
||||||
|
# print("Lze",obj,new_parent)
|
||||||
|
return True
|
||||||
|
if textOnlySubtree(obj):
|
||||||
|
# print("Lze",obj,new_parent)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def canPodvesitZa(value):
|
||||||
|
if not value.index or value.index+1 >= len(value.parent.children):
|
||||||
|
return False
|
||||||
|
new_parent = value.parent.children[value.index+1]
|
||||||
|
return canPodvesit(value,new_parent)
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def canPodvesitPred(value):
|
||||||
|
if not value.index or value.index <= 0:
|
||||||
|
return False
|
||||||
|
new_parent = value.parent.children[value.index-1]
|
||||||
|
return canPodvesit(value,new_parent)
|
||||||
|
|
||||||
|
|
||||||
|
class NodeTypes(Enum):
|
||||||
|
ROCNIK = ('rocnikNode','Ročník')
|
||||||
|
CISLO = ('cisloNode', 'Číslo')
|
||||||
|
MEZICISLO = ('mezicisloNode', 'Mezičíslo')
|
||||||
|
CAST = ('castNode', 'Část')
|
||||||
|
TEXT = ('textNode', 'Text')
|
||||||
|
TEMAVCISLE = ('temaVCisleNode', 'Téma v čísle')
|
||||||
|
RESENI = ('reseniNode','Řešení')
|
||||||
|
ULOHAZADANI = ('ulohaZadaniNode','Zadání')
|
||||||
|
ULOHAVZORAK = ('ulohaVzorakNode','Vzorák')
|
||||||
|
POHADKA = ('pohadkaNode','Pohádka')
|
||||||
|
ORGTEXT = ('orgText','Orgtext')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def appendableChildren(value):
|
||||||
|
print(value)
|
||||||
|
print(value.node)
|
||||||
|
print(isUlohaZadani(value.node))
|
||||||
|
if isTemaVCisle(value.node):
|
||||||
|
return (NodeTypes.RESENI.value[0],
|
||||||
|
NodeTypes.ULOHAZADANI.value[0],
|
||||||
|
NodeTypes.ULOHAVZORAK.value[0],
|
||||||
|
NodeTypes.CAST.value[0],
|
||||||
|
NodeTypes.TEXT.value[0],
|
||||||
|
)
|
||||||
|
if isOrgText(value.node) or isReseni(value.node) or isUlohaZadani(value.node) or isUlohaVzorak(value.node):
|
||||||
|
print("Text/Cast")
|
||||||
|
return (NodeTypes.CAST.value[0],
|
||||||
|
NodeTypes.TEXT.value[0],
|
||||||
|
)
|
||||||
|
if isCast(value.node):
|
||||||
|
return appendableChildren(value.parent)
|
||||||
|
return []
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def canAppendReseni(value):
|
||||||
|
if isTemaVCisle(value.node):
|
||||||
|
return True
|
||||||
|
if isCast(value.node):
|
||||||
|
return canAppendReseni(value.parent)
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def canAppendUlohaZadani(value):
|
||||||
|
if isTemaVCisle(value.node):
|
||||||
|
return True
|
||||||
|
if isCast(value.node):
|
||||||
|
return canAppendUlohaZadani(value.parent)
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def canAppendUlohaVzorak(value):
|
||||||
|
if isTemaVCisle(value.node):
|
||||||
|
return True
|
||||||
|
if isCast(value.node):
|
||||||
|
return canAppendUlohaVzorak(value.parent)
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def canAppendCast(value):
|
||||||
|
if isTemaVCisle(value.node) or isOrgText(value.node) or isReseni(value.node) or isUlohaZadani(value.node) or isUlohaVzorak(value.node):
|
||||||
|
return True
|
||||||
|
if isCast(value.node):
|
||||||
|
return canAppendCast(value.parent)
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def canAppendText(value):
|
||||||
|
if isTemaVCisle(value.node) or isOrgText(value.node) or isReseni(value.node) or isUlohaZadani(value.node) or isUlohaVzorak(value.node):
|
||||||
|
return True
|
||||||
|
if isCast(value.node):
|
||||||
|
return canAppendText(value.parent)
|
||||||
|
return False
|
||||||
|
|
||||||
|
#@register.filter
|
||||||
|
#def is(value):
|
||||||
|
# return
|
||||||
|
#
|
||||||
|
# NodeTypes..value,
|
||||||
|
#@register.filter
|
||||||
|
#def is(value):
|
||||||
|
# return
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ def gen_resitele(rnd, osoby, skoly):
|
||||||
x += 1
|
x += 1
|
||||||
os.user = user
|
os.user = user
|
||||||
os.save()
|
os.save()
|
||||||
os.user.user_permissions.add(resitel_perm)
|
os.user.user_permissions.add(resitel_perm)
|
||||||
resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice(skoly),
|
resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice(skoly),
|
||||||
rok_maturity=rnd.randint(2019, 2029),
|
rok_maturity=rnd.randint(2019, 2029),
|
||||||
zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0]))
|
zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0]))
|
||||||
|
@ -199,7 +199,7 @@ def gen_organizatori(rnd, osoby, last_rocnik):
|
||||||
x += 1
|
x += 1
|
||||||
os.user = user
|
os.user = user
|
||||||
os.save()
|
os.save()
|
||||||
os.user.user_permissions.add(org_perm)
|
os.user.user_permissions.add(org_perm)
|
||||||
organizatori.append(Organizator.objects.create(osoba=os,
|
organizatori.append(Organizator.objects.create(osoba=os,
|
||||||
organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga))
|
organizuje_od=od, organizuje_do=do, strucny_popis_organizatora = popis_orga))
|
||||||
return organizatori
|
return organizatori
|
||||||
|
@ -244,8 +244,8 @@ def gen_zadani_ulohy(rnd, cisla, organizatori, pocet_oboru, poradi_cisla, poradi
|
||||||
na_web = text,
|
na_web = text,
|
||||||
do_cisla = text,
|
do_cisla = text,
|
||||||
)
|
)
|
||||||
zad = TextNode.objects.create(text = text_zadani)
|
zad = TextNode.objects.create(text = text_zadani, root = p.cislo_zadani.rocnik.rocniknode)
|
||||||
uloha_zadani = UlohaZadaniNode.objects.create(uloha = p, first_child = zad)
|
uloha_zadani = UlohaZadaniNode.objects.create(uloha = p, first_child = zad, root = p.cislo_zadani.rocnik.rocniknode)
|
||||||
p.ulohazadaninode = uloha_zadani
|
p.ulohazadaninode = uloha_zadani
|
||||||
otec_syn(cisla[poradi_cisla-2-1].cislonode, uloha_zadani)
|
otec_syn(cisla[poradi_cisla-2-1].cislonode, uloha_zadani)
|
||||||
|
|
||||||
|
@ -266,8 +266,8 @@ def gen_vzoroveho_reseni_ulohy(rnd, organizatori, uloha, pocet_opravovatelu):
|
||||||
na_web = obsah,
|
na_web = obsah,
|
||||||
do_cisla = obsah
|
do_cisla = obsah
|
||||||
)
|
)
|
||||||
vzorak = TextNode.objects.create(text = text_vzoraku)
|
vzorak = TextNode.objects.create(text = text_vzoraku, root = uloha.cislo_zadani.rocnik.rocniknode)
|
||||||
uloha_vzorak = UlohaVzorakNode.objects.create(uloha = uloha, first_child = vzorak)
|
uloha_vzorak = UlohaVzorakNode.objects.create(uloha = uloha, first_child = vzorak, root = uloha.cislo_zadani.rocnik.rocniknode)
|
||||||
uloha.ulohavzoraknode = uloha_vzorak
|
uloha.ulohavzoraknode = uloha_vzorak
|
||||||
|
|
||||||
uloha.opravovatele.set(rnd.sample(organizatori, pocet_opravovatelu))
|
uloha.opravovatele.set(rnd.sample(organizatori, pocet_opravovatelu))
|
||||||
|
@ -434,7 +434,7 @@ def gen_cisla(rnd, rocniky):
|
||||||
datum_deadline=deadline,
|
datum_deadline=deadline,
|
||||||
verejne_db=True
|
verejne_db=True
|
||||||
)
|
)
|
||||||
node2 = CisloNode.objects.create(cislo = cislo, succ = node)
|
node2 = CisloNode.objects.create(cislo = cislo, succ = node, root=rocnik.rocniknode)
|
||||||
cislo.save()
|
cislo.save()
|
||||||
node = node2
|
node = node2
|
||||||
if otec:
|
if otec:
|
||||||
|
@ -473,54 +473,54 @@ def gen_dlouhe_tema(rnd, organizatori, rocnik, nazev, obor, kod):
|
||||||
for cislo in cisla:
|
for cislo in cisla:
|
||||||
# Přidáme TemaVCisleNode do daného čísla
|
# Přidáme TemaVCisleNode do daného čísla
|
||||||
cislo_node = cislo.cislonode
|
cislo_node = cislo.cislonode
|
||||||
tema_cislo_node = TemaVCisleNode.objects.create(tema = tema)
|
tema_cislo_node = TemaVCisleNode.objects.create(tema = tema, root = cislo_node.root)
|
||||||
insert_last_child(cislo_node, tema_cislo_node)
|
insert_last_child(cislo_node, tema_cislo_node)
|
||||||
|
|
||||||
# Přidávání obsahu do čísla
|
# Přidávání obsahu do čísla
|
||||||
cast_node = m.CastNode.objects.create(nadpis = "Příspěvek k číslu {}".format(cislo.kod))
|
cast_node = m.CastNode.objects.create(nadpis = "Příspěvek k číslu {}".format(cislo.kod), root=cislo_node.root)
|
||||||
add_first_child(tema_cislo_node, cast_node)
|
add_first_child(tema_cislo_node, cast_node)
|
||||||
|
|
||||||
text_node = TextNode.objects.create(text = get_text())
|
text_node = TextNode.objects.create(text = get_text(), root=cislo_node.root)
|
||||||
add_first_child(cast_node, text_node)
|
add_first_child(cast_node, text_node)
|
||||||
|
|
||||||
cast_node2 = m.CastNode.objects.create(nadpis = "První podproblém")
|
cast_node2 = m.CastNode.objects.create(nadpis = "První podproblém", root=cislo_node.root)
|
||||||
add_first_child(text_node, cast_node2)
|
add_first_child(text_node, cast_node2)
|
||||||
|
|
||||||
text_node2 = TextNode.objects.create(text = get_text())
|
text_node2 = TextNode.objects.create(text = get_text(), root=cislo_node.root)
|
||||||
add_first_child(cast_node2, text_node2)
|
add_first_child(cast_node2, text_node2)
|
||||||
|
|
||||||
cast_node3 = m.CastNode.objects.create(nadpis = "Druhý podproblém")
|
cast_node3 = m.CastNode.objects.create(nadpis = "Druhý podproblém", root=cislo_node.root)
|
||||||
add_first_child(text_node2, cast_node3)
|
add_first_child(text_node2, cast_node3)
|
||||||
|
|
||||||
text_node3 = TextNode.objects.create(text = get_text())
|
text_node3 = TextNode.objects.create(text = get_text(), root=cislo_node.root)
|
||||||
add_first_child(cast_node3, text_node3)
|
add_first_child(cast_node3, text_node3)
|
||||||
|
|
||||||
cast_node4 = m.CastNode.objects.create(nadpis = "Třetí podproblém")
|
cast_node4 = m.CastNode.objects.create(nadpis = "Třetí podproblém", root=cislo_node.root)
|
||||||
add_first_child(text_node3, cast_node4)
|
add_first_child(text_node3, cast_node4)
|
||||||
|
|
||||||
text_node4 = TextNode.objects.create(text = get_text())
|
text_node4 = TextNode.objects.create(text = get_text(), root=cislo_node.root)
|
||||||
add_first_child(cast_node3, text_node4)
|
add_first_child(cast_node3, text_node4)
|
||||||
|
|
||||||
cast_node3a = m.CastNode.objects.create(nadpis = "Podproblém paralelní s "
|
cast_node3a = m.CastNode.objects.create(nadpis = "Podproblém paralelní s "
|
||||||
"druhým podproblémem")
|
"druhým podproblémem", root=cislo_node.root)
|
||||||
cast_node3.succ = cast_node3a
|
cast_node3.succ = cast_node3a
|
||||||
cast_node3.save()
|
cast_node3.save()
|
||||||
|
|
||||||
text_node3a = TextNode.objects.create(text = get_text())
|
text_node3a = TextNode.objects.create(text = get_text(), root=cislo_node.root)
|
||||||
add_first_child(cast_node3a, text_node3a)
|
add_first_child(cast_node3a, text_node3a)
|
||||||
|
|
||||||
# Občas přidáme mezičíslo
|
# Občas přidáme mezičíslo
|
||||||
if rnd.randint(1, 3) == 1:
|
if rnd.randint(1, 3) == 1:
|
||||||
create_node_after(cislo_node, m.MezicisloNode)
|
create_node_after(cislo_node, m.MezicisloNode, root=cislo_node.root)
|
||||||
mezicislo_node = cislo_node.succ
|
mezicislo_node = cislo_node.succ
|
||||||
|
|
||||||
cast_node_mezicislo = m.CastNode.objects.create(
|
cast_node_mezicislo = m.CastNode.objects.create(
|
||||||
nadpis = "Příspěvek k mezičíslu".format(cislo.kod))
|
nadpis = "Příspěvek k mezičíslu".format(cislo.kod), root=cislo_node.root)
|
||||||
add_first_child(mezicislo_node, cast_node_mezicislo)
|
add_first_child(mezicislo_node, cast_node_mezicislo)
|
||||||
|
|
||||||
odstavec = lorem.paragraph()
|
odstavec = lorem.paragraph()
|
||||||
text_mezicislo = Text.objects.create(na_web = odstavec, do_cisla = odstavec)
|
text_mezicislo = Text.objects.create(na_web = odstavec, do_cisla = odstavec)
|
||||||
text_node_mezicislo = TextNode.objects.create(text = text_mezicislo)
|
text_node_mezicislo = TextNode.objects.create(text = text_mezicislo, root=cislo_node.root)
|
||||||
add_first_child(cast_node_mezicislo, text_node_mezicislo)
|
add_first_child(cast_node_mezicislo, text_node_mezicislo)
|
||||||
|
|
||||||
return tema
|
return tema
|
||||||
|
@ -564,7 +564,7 @@ def gen_temata(rnd, rocniky, rocnik_cisla, organizatori):
|
||||||
|
|
||||||
# Vyrobíme TemaVCisleNody pro obsah
|
# Vyrobíme TemaVCisleNody pro obsah
|
||||||
for i in range(zacatek_tematu, konec_tematu+1):
|
for i in range(zacatek_tematu, konec_tematu+1):
|
||||||
node = TemaVCisleNode.objects.create(tema = t)
|
node = TemaVCisleNode.objects.create(tema = t,root=rocnik.rocniknode)
|
||||||
# FIXME: Není to off-by-one?
|
# FIXME: Není to off-by-one?
|
||||||
otec = cisla[i-1].cislonode
|
otec = cisla[i-1].cislonode
|
||||||
otec_syn(otec, node)
|
otec_syn(otec, node)
|
||||||
|
@ -621,8 +621,8 @@ def gen_ulohy_tematu(rnd, organizatori, tema, kod, cislo, cislo_se_vzorakem):
|
||||||
na_web = obsah,
|
na_web = obsah,
|
||||||
do_cisla = obsah,
|
do_cisla = obsah,
|
||||||
)
|
)
|
||||||
zad = TextNode.objects.create(text = text_zadani)
|
zad = TextNode.objects.create(text = text_zadani, root=tema.temavcislenode_set.first().root)
|
||||||
uloha_zadani = UlohaZadaniNode.objects.create(uloha=uloha, first_child = zad)
|
uloha_zadani = UlohaZadaniNode.objects.create(uloha=uloha, first_child = zad, root=tema.temavcislenode_set.first().root)
|
||||||
uloha.ulohazadaninode = uloha_zadani
|
uloha.ulohazadaninode = uloha_zadani
|
||||||
|
|
||||||
return uloha, uloha_zadani
|
return uloha, uloha_zadani
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.db import transaction
|
||||||
# NOTE: node.prev a node.succ jsou implementovány přímo v models.TreeNode
|
# NOTE: node.prev a node.succ jsou implementovány přímo v models.TreeNode
|
||||||
# TODO: Všechny tyto funkce se naivně spoléhají na to, že jako parametr dostanou nějaký TreeNode (některé možná zvládnou i None)
|
# TODO: Všechny tyto funkce se naivně spoléhají na to, že jako parametr dostanou nějaký TreeNode (některé možná zvládnou i None)
|
||||||
# TODO: Chceme, aby všechno nějak zvládlo None jako parametr.
|
# TODO: Chceme, aby všechno nějak zvládlo None jako parametr.
|
||||||
|
# TODO: Do nějakých consistency-checků přidat hledání polo-sirotků (kteří nesplňují invarianty, třeba nejsou dosažitelní a mají root, vyrábějí DAG, ...)
|
||||||
|
|
||||||
# Slouží k debugování pro rychlé získání představy o podobě podstromu pod tímto TreeNode.
|
# Slouží k debugování pro rychlé získání představy o podobě podstromu pod tímto TreeNode.
|
||||||
def print_tree(node,indent=0):
|
def print_tree(node,indent=0):
|
||||||
|
@ -12,20 +14,31 @@ def print_tree(node,indent=0):
|
||||||
if node.succ:
|
if node.succ:
|
||||||
print_tree(node.succ, indent=indent)
|
print_tree(node.succ, indent=indent)
|
||||||
|
|
||||||
def is_orphan(node):
|
|
||||||
""" Zjišťuje, jestli už je daný Node někde pověšený či nikoli. """
|
|
||||||
if safe_father_of_first(node) is None and safe_pred(node) is None:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Django je trošku hloupé, takže node.prev nevrací None, ale hází django.core.exceptions.ObjectDoesNotExist
|
# Django je trošku hloupé, takže node.prev nevrací None, ale hází django.core.exceptions.ObjectDoesNotExist
|
||||||
def safe_pred(node):
|
def safe_pred(node):
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
return node.prev
|
return node.prev
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# FIXME: Proč?????
|
||||||
|
def safe_succ(node):
|
||||||
|
try:
|
||||||
|
return node.succ
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def safe_father_of_first(node):
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
|
first = first_brother(node)
|
||||||
|
try:
|
||||||
|
return first.father_of_first
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
def first_brother(node):
|
def first_brother(node):
|
||||||
if node is None:
|
if node is None:
|
||||||
return None
|
return None
|
||||||
|
@ -34,15 +47,8 @@ def first_brother(node):
|
||||||
brother = safe_pred(brother)
|
brother = safe_pred(brother)
|
||||||
return brother
|
return brother
|
||||||
|
|
||||||
# A to samé pro .father_of_first
|
|
||||||
def safe_father_of_first(node):
|
|
||||||
first = first_brother(node)
|
|
||||||
try:
|
|
||||||
return first.father_of_first
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
return None
|
|
||||||
|
|
||||||
## Rodinné vztahy
|
## Rodinné vztahy
|
||||||
|
# Tohle se teď zrovna k None chová správně, ale je potřeba na to dávat pozor
|
||||||
def get_parent(node):
|
def get_parent(node):
|
||||||
# Nejdřív získáme prvního potomka...
|
# Nejdřív získáme prvního potomka...
|
||||||
while safe_pred(node) is not None:
|
while safe_pred(node) is not None:
|
||||||
|
@ -51,14 +57,33 @@ def get_parent(node):
|
||||||
return safe_father_of_first(node)
|
return safe_father_of_first(node)
|
||||||
|
|
||||||
def get_last_child(node):
|
def get_last_child(node):
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
first = node.first_child
|
first = node.first_child
|
||||||
if first is None:
|
if first is None:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return last_brother(first)
|
return last_brother(first)
|
||||||
|
|
||||||
|
def is_orphan(node):
|
||||||
|
""" Zjišťuje, jestli už je daný Node někde pověšený či nikoli. """
|
||||||
|
# None jsem se rozhodl, že sirotek není
|
||||||
|
if node is None:
|
||||||
|
return False
|
||||||
|
if get_parent(node) is None:
|
||||||
|
if node.succ is not None or safe_pred(node) is not None or safe_father_of_first(node) is not None or node.root is not None:
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
# Error = pošle mail :-)
|
||||||
|
logger.error(f"Node-sirotek s id {node.id} má rodinné vztahy (Node: {node})")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
# Obecný next: další Node v "the-right-order" pořadí (já, pak potomci, pak sousedé)
|
# Obecný next: další Node v "the-right-order" pořadí (já, pak potomci, pak sousedé)
|
||||||
def general_next(node):
|
def general_next(node):
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
# Máme potomka?
|
# Máme potomka?
|
||||||
if node.first_child is not None:
|
if node.first_child is not None:
|
||||||
return node.first_child
|
return node.first_child
|
||||||
|
@ -71,6 +96,8 @@ def general_next(node):
|
||||||
return node.succ
|
return node.succ
|
||||||
|
|
||||||
def last_brother(node):
|
def last_brother(node):
|
||||||
|
if node is None:
|
||||||
|
return None
|
||||||
while node.succ is not None:
|
while node.succ is not None:
|
||||||
node = node.succ
|
node = node.succ
|
||||||
return node
|
return node
|
||||||
|
@ -78,6 +105,7 @@ def last_brother(node):
|
||||||
def general_prev(node):
|
def general_prev(node):
|
||||||
# Předchůdce je buď rekurzivně poslední potomek předchůdce, nebo náš otec.
|
# Předchůdce je buď rekurzivně poslední potomek předchůdce, nebo náš otec.
|
||||||
# Otce vyřešíme nejdřív:
|
# Otce vyřešíme nejdřív:
|
||||||
|
# Tady se ošetří node=None samo
|
||||||
if safe_pred(node) is None:
|
if safe_pred(node) is None:
|
||||||
return safe_father_of_first(node)
|
return safe_father_of_first(node)
|
||||||
pred = safe_pred(node)
|
pred = safe_pred(node)
|
||||||
|
@ -95,12 +123,16 @@ def me_and_right_brothers(node):
|
||||||
current = current.succ
|
current = current.succ
|
||||||
|
|
||||||
def right_brothers(node):
|
def right_brothers(node):
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
generator = me_and_right_brothers(node.succ)
|
generator = me_and_right_brothers(node.succ)
|
||||||
for item in generator:
|
for item in generator:
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
# Generátor všech sourozenců (vč. sám sebe)
|
# Generátor všech sourozenců (vč. sám sebe)
|
||||||
def all_brothers(node):
|
def all_brothers(node):
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
# Najdeme prvního bratra
|
# Najdeme prvního bratra
|
||||||
fb = first_brother(node)
|
fb = first_brother(node)
|
||||||
marb = me_and_right_brothers(fb)
|
marb = me_and_right_brothers(fb)
|
||||||
|
@ -108,6 +140,8 @@ def all_brothers(node):
|
||||||
yield cur
|
yield cur
|
||||||
|
|
||||||
def all_proper_brothers(node):
|
def all_proper_brothers(node):
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
all = all_brothers(node)
|
all = all_brothers(node)
|
||||||
for br in all:
|
for br in all:
|
||||||
if br is node:
|
if br is node:
|
||||||
|
@ -116,12 +150,16 @@ def all_proper_brothers(node):
|
||||||
|
|
||||||
def all_children(node):
|
def all_children(node):
|
||||||
""" Generátor všech potomků zadaného Node. """
|
""" Generátor všech potomků zadaného Node. """
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
brothers = all_brothers(node.first_child)
|
brothers = all_brothers(node.first_child)
|
||||||
for br in brothers:
|
for br in brothers:
|
||||||
yield br
|
yield br
|
||||||
|
|
||||||
def all_children_of_type(node, type):
|
def all_children_of_type(node, type):
|
||||||
""" Generuje všechny potomky daného Node a daného typu. """
|
""" Generuje všechny potomky daného Node a daného typu. """
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
brothers = all_brothers(node.first_child)
|
brothers = all_brothers(node.first_child)
|
||||||
for br in brothers:
|
for br in brothers:
|
||||||
if isinstance(br, type):
|
if isinstance(br, type):
|
||||||
|
@ -130,6 +168,8 @@ def all_children_of_type(node, type):
|
||||||
# Generátor následníků v "the-right-order"
|
# Generátor následníků v "the-right-order"
|
||||||
# Bez tohoto vrcholu
|
# Bez tohoto vrcholu
|
||||||
def all_following(node):
|
def all_following(node):
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
current = general_next(node)
|
current = general_next(node)
|
||||||
while current is not None:
|
while current is not None:
|
||||||
yield current
|
yield current
|
||||||
|
@ -139,12 +179,16 @@ def all_following(node):
|
||||||
# Najdi dalšího bratra nějakého typu, nebo None.
|
# Najdi dalšího bratra nějakého typu, nebo None.
|
||||||
# hledá i podtřídy, i.e. get_next_brother_of_type(neco, TreeNode) je prostě succ.
|
# hledá i podtřídy, i.e. get_next_brother_of_type(neco, TreeNode) je prostě succ.
|
||||||
def get_next_brother_of_type(node, type):
|
def get_next_brother_of_type(node, type):
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
for current in right_brothers(node):
|
for current in right_brothers(node):
|
||||||
if isinstance(current, type):
|
if isinstance(current, type):
|
||||||
return current
|
return current
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_prev_brother_of_type(node, type):
|
def get_prev_brother_of_type(node, type):
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
# Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem.
|
# Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem.
|
||||||
current = node
|
current = node
|
||||||
while safe_pred(current) is not None:
|
while safe_pred(current) is not None:
|
||||||
|
@ -155,6 +199,8 @@ def get_prev_brother_of_type(node, type):
|
||||||
|
|
||||||
# Totéž pro "the-right-order" pořadí
|
# Totéž pro "the-right-order" pořadí
|
||||||
def get_next_node_of_type(node, type):
|
def get_next_node_of_type(node, type):
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
for cur in all_folowing(node):
|
for cur in all_folowing(node):
|
||||||
if isinstance(cur, type):
|
if isinstance(cur, type):
|
||||||
return cur
|
return cur
|
||||||
|
@ -162,6 +208,8 @@ def get_next_node_of_type(node, type):
|
||||||
|
|
||||||
def get_prev_node_of_type(node, type):
|
def get_prev_node_of_type(node, type):
|
||||||
# Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem.
|
# Na tohle není rozumný generátor, ani ho asi nechceme, prostě to implementujeme cyklem.
|
||||||
|
if node is None:
|
||||||
|
return
|
||||||
current = node
|
current = node
|
||||||
while general_prev(current) is not None:
|
while general_prev(current) is not None:
|
||||||
current = general_prev(current)
|
current = general_prev(current)
|
||||||
|
@ -171,20 +219,38 @@ def get_prev_node_of_type(node, type):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Exception, kterou některé metody při špatném použití mohou házet
|
||||||
|
# Hlavní důvod je možnost informovat o selhání, aby se příslušný problém dal zobrazit na frontendu,
|
||||||
|
class TreeLibError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Editace stromu:
|
# Editace stromu:
|
||||||
def create_node_after(predecessor, type, **kwargs):
|
def create_node_after(predecessor, type, **kwargs):
|
||||||
|
from seminar.models import TreeNode
|
||||||
|
if predecessor is None:
|
||||||
|
raise TreeLibError("Nelze vyrábět sirotky! (predecessor=None)")
|
||||||
|
if not issubclass(type, TreeNode):
|
||||||
|
raise TreeLibError("Nový node není node!")
|
||||||
new_node = type.objects.create(**kwargs)
|
new_node = type.objects.create(**kwargs)
|
||||||
|
new_node.root = predecessor.root
|
||||||
new_node.save()
|
new_node.save()
|
||||||
succ = predecessor.succ
|
succ = predecessor.succ
|
||||||
predecessor.succ = new_node
|
predecessor.succ = new_node
|
||||||
predecessor.save()
|
predecessor.save()
|
||||||
new_node.succ = succ
|
new_node.succ = succ
|
||||||
new_node.save()
|
new_node.save()
|
||||||
|
return new_node
|
||||||
|
|
||||||
# Vyrábí prvního syna, ostatní nalepí za (existují-li)
|
# Vyrábí prvního syna, ostatní nalepí za (existují-li)
|
||||||
def create_child(parent, type, **kwargs):
|
def create_child(parent, type, **kwargs):
|
||||||
|
from seminar.models import TreeNode
|
||||||
|
if parent is None:
|
||||||
|
raise TreeLibError("Nelze vyrábět sirotky! (parent=None)")
|
||||||
|
if not issubclass(type, TreeNode):
|
||||||
|
raise TreeLibError("Nový node není node!")
|
||||||
new_node = type.objects.create(**kwargs)
|
new_node = type.objects.create(**kwargs)
|
||||||
|
new_node.root = parent.root
|
||||||
new_node.save()
|
new_node.save()
|
||||||
orig_child = parent.first_child
|
orig_child = parent.first_child
|
||||||
parent.first_child = new_node
|
parent.first_child = new_node
|
||||||
|
@ -193,8 +259,11 @@ def create_child(parent, type, **kwargs):
|
||||||
# Přidáme původního prvního syna jako potomka nového vrcholu
|
# Přidáme původního prvního syna jako potomka nového vrcholu
|
||||||
new_node.succ = orig_child
|
new_node.succ = orig_child
|
||||||
new_node.save()
|
new_node.save()
|
||||||
|
return new_node
|
||||||
|
|
||||||
def insert_last_child(parent, node):
|
def insert_last_child(parent, node):
|
||||||
|
if parent is None:
|
||||||
|
raise TreeLibError("Nelze vyrábět sirotky! (parent=None)")
|
||||||
""" Zadaný Node přidá jako posledního potomka otce. """
|
""" Zadaný Node přidá jako posledního potomka otce. """
|
||||||
last = get_last_child(parent)
|
last = get_last_child(parent)
|
||||||
if not is_orphan(node):
|
if not is_orphan(node):
|
||||||
|
@ -213,6 +282,11 @@ def insert_last_child(parent, node):
|
||||||
last.save()
|
last.save()
|
||||||
|
|
||||||
def create_node_before(successor, type, **kwargs):
|
def create_node_before(successor, type, **kwargs):
|
||||||
|
from seminar.models import TreeNode
|
||||||
|
if successor is None:
|
||||||
|
raise TreeLibError("Nelze vyrábět sirotky! (successor=None)")
|
||||||
|
if not issubclass(type, TreeNode):
|
||||||
|
raise TreeLibError("Nový node není node!")
|
||||||
if safe_pred(successor) is not None:
|
if safe_pred(successor) is not None:
|
||||||
# Easy: přidáme za předchůdce
|
# Easy: přidáme za předchůdce
|
||||||
create_node_after(successor.prev, type, **kwargs)
|
create_node_after(successor.prev, type, **kwargs)
|
||||||
|
@ -223,36 +297,18 @@ def create_node_before(successor, type, **kwargs):
|
||||||
create_child(successor.father_of_first, type, **kwargs)
|
create_child(successor.father_of_first, type, **kwargs)
|
||||||
# Teď už easy: Jsme sirotci, takže se vyrobíme a našeho následníka si přidáme jako succ
|
# Teď už easy: Jsme sirotci, takže se vyrobíme a našeho následníka si přidáme jako succ
|
||||||
new = type.objects.create(**kwargs)
|
new = type.objects.create(**kwargs)
|
||||||
|
new.root = successor.root
|
||||||
new.succ = successor
|
new.succ = successor
|
||||||
new.save()
|
new.save()
|
||||||
|
return new
|
||||||
|
|
||||||
|
|
||||||
# ValueError, pokud je (aspoň) jeden parametr None
|
# ValueError, pokud je (aspoň) jeden parametr None
|
||||||
def swap(node, other):
|
def swap(node, other):
|
||||||
raise NotImplementedError("YAGNI (You aren't gonna need it).")
|
raise NotImplementedError("YAGNI (You aren't gonna need it).")
|
||||||
|
|
||||||
# Exception, kterou některé metody při špatném použití mohou házet
|
|
||||||
# Hlavní důvod je možnost informovat o selhání, aby se příslušný problém dal zobrazit na frontendu,
|
|
||||||
class TreeLibError(RuntimeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def swap_pred(node):
|
|
||||||
if node is None:
|
|
||||||
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
|
||||||
pred = safe_pred(node)
|
|
||||||
if pred is None:
|
|
||||||
raise TreeLibError("Nelze posunout vlevo, není tam žádný další uzel.")
|
|
||||||
pre_pred = safe_pred(pred)
|
|
||||||
succ = node.succ
|
|
||||||
|
|
||||||
if pre_pred is not None:
|
|
||||||
pre_pred.succ = node
|
|
||||||
pre_pred.save()
|
|
||||||
node.succ = pred
|
|
||||||
node.save()
|
|
||||||
pred.succ = succ
|
|
||||||
pred.save()
|
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def swap_succ(node):
|
def swap_succ(node):
|
||||||
if node is None:
|
if node is None:
|
||||||
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
||||||
|
@ -263,63 +319,147 @@ def swap_succ(node):
|
||||||
post_succ = succ.succ
|
post_succ = succ.succ
|
||||||
|
|
||||||
if pred is not None:
|
if pred is not None:
|
||||||
pred.succ = succ
|
pred.succ = None
|
||||||
pred.save()
|
pred.save()
|
||||||
|
|
||||||
|
# Nemame predchudce -> je potreba upravit otce
|
||||||
|
father = safe_father_of_first(node)
|
||||||
|
if pred is None and father is not None: # Mame otce
|
||||||
|
father.first_child = succ
|
||||||
|
father.save()
|
||||||
|
|
||||||
|
|
||||||
succ.succ = node
|
succ.succ = node
|
||||||
succ.save()
|
succ.save()
|
||||||
node.succ = post_succ
|
node.succ = post_succ
|
||||||
node.save()
|
node.save()
|
||||||
|
if pred is not None:
|
||||||
|
pred.succ = succ
|
||||||
|
pred.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def swap_pred(node):
|
||||||
|
if node is None:
|
||||||
|
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
||||||
|
pred = safe_pred(node)
|
||||||
|
if pred is None:
|
||||||
|
raise TreeLibError("Nelze posunout vlevo, není tam žádný další uzel.")
|
||||||
|
return swap_succ(pred)
|
||||||
|
|
||||||
# Rotace stromu
|
# Rotace stromu
|
||||||
# Dokumentace viz wiki:
|
# Dokumentace viz wiki:
|
||||||
# (lower bude jednoduchá rotace, ne mega, existence jednoduché rotace mi došla až po nakreslení obrázku)
|
|
||||||
def raise_node(node):
|
def raise_node(node):
|
||||||
if node is None:
|
if node is None:
|
||||||
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
||||||
# Pojmenování viz WIKI (as of 2020-03-19 01:33:44 GMT+1)
|
# Pojmenování viz WIKI (as of 2020-03-19 01:33:44 GMT+1)
|
||||||
# FIXME: Velmi naivní, chybí error checky
|
# FIXME: Trochu méně naivní, nevěřím tomu, prosím otestovat
|
||||||
D = node
|
D = node
|
||||||
C = get_parent(D)
|
C = get_parent(D)
|
||||||
E = C.succ
|
if C is None:
|
||||||
subtree4_head = D.first_child
|
raise TreeLibError("Nelze povýšit vrchol, jenž nemá otce.")
|
||||||
subtree4_tail = last_brother(subtree4_head)
|
E = C.succ # Může být None a ničemu to nevadí
|
||||||
subtree3P_head = D.succ
|
subtree4_head = D.first_child # Může být None, ale pak se musí z 3P udělat přímo potomek D
|
||||||
subtree3L_head = C.first_child
|
subtree4_tail = last_brother(subtree4_head) # Měl by být None právě když je sub4_head=None
|
||||||
subtree3L_tail = safe_pred(D)
|
subtree3P_head = D.succ # Může být None a ničemu to nevadí
|
||||||
|
subtree3L_tail = safe_pred(D) # Pokud je None, D je první syn C a C má tedy skončit bezdětný
|
||||||
|
|
||||||
# Prostor pro motlitbu...
|
# Prostor pro motlitbu...
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Amen.
|
# Amen.
|
||||||
C.succ = D
|
# Teď už nesmíme spadnout, protože jinak skončíme se stromem v nekonzistentním stavu
|
||||||
|
C.succ = D # Nespadne
|
||||||
C.save()
|
C.save()
|
||||||
D.succ = E
|
D.succ = E # Nespadne
|
||||||
D.save()
|
D.save()
|
||||||
subtree3L_tail.succ = None
|
|
||||||
subtree3L_tail.save()
|
if subtree3L_tail is not None:
|
||||||
subtree4_tail.succ = subtree3P.head
|
subtree3L_tail.succ = None
|
||||||
subtree4_tail.save()
|
subtree3L_tail.save()
|
||||||
|
else:
|
||||||
|
assert C.first_child is D
|
||||||
|
C.first_child = None
|
||||||
|
C.save()
|
||||||
|
|
||||||
|
if subtree4_tail is not None:
|
||||||
|
subtree4_tail.succ = subtree3P_head
|
||||||
|
subtree4_tail.save()
|
||||||
|
else:
|
||||||
|
D.first_child = subtree3P_head
|
||||||
|
D.save()
|
||||||
|
|
||||||
# To by mělo být všechno...
|
# To by mělo být všechno...
|
||||||
|
|
||||||
|
# (lower bude jednoduchá rotace, ne mega, existence jednoduché rotace mi došla až po nakreslení obrázku)
|
||||||
def lower_node(node):
|
def lower_node(node):
|
||||||
if node is None:
|
if node is None:
|
||||||
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
raise TreeLibError("Nelze přesunout None. Tohle by se nemělo stát.")
|
||||||
# Pojmenování viz WIKI (as of 2020-03-19 01:33:44 GMT+1)
|
# Pojmenování viz WIKI (as of 2020-03-19 01:33:44 GMT+1)
|
||||||
# FIXME: Velmi naivní, chybí error checky
|
# FIXME: Trochu naivní, prosím otestovat
|
||||||
C = node
|
C = node
|
||||||
D = C.succ
|
D = C.succ # Může být None a ničemu to nevadí
|
||||||
B = safe_pred(C)
|
B = safe_pred(C)
|
||||||
subtree2_head = B.first_child
|
if B is None:
|
||||||
subtree2_tail = last_brother(subtree2_head)
|
raise TreeLibError("Nelze ponížit prvního syna (není pod co)")
|
||||||
|
subtree2_head = B.first_child # Je-li None, pak se z C má stát první syn
|
||||||
|
subtree2_tail = last_brother(subtree2_head) # None iff head=None, doufám
|
||||||
|
|
||||||
# Prostor pro motlitbu...
|
# Prostor pro motlitbu...
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Amen.
|
# Amen.
|
||||||
B.succ = D
|
# Teď už nesmíme spadnout, protože jinak skončíme se stromem v nekonzistentním stavu
|
||||||
|
B.succ = D # Nespadne
|
||||||
B.save()
|
B.save()
|
||||||
subtree2_tail.succ = C
|
if subtree2_tail is not None:
|
||||||
subtree2_tail.save()
|
subtree2_tail.succ = C
|
||||||
|
subtree2_tail.save()
|
||||||
|
else:
|
||||||
|
assert subtree2_head is None
|
||||||
|
B.first_child = C
|
||||||
|
B.save()
|
||||||
|
|
||||||
# To by mělo být všechno...
|
# To by mělo být všechno...
|
||||||
|
|
||||||
|
def disconnect_node(node):
|
||||||
|
#FIXME: dodělat odstranění roota všem potomkům
|
||||||
|
if node is None:
|
||||||
|
raise TreeLibError("Nelze odpojit None. Tohle by se nemělo stát.")
|
||||||
|
|
||||||
|
print(f'My:{node}, predchudce:{safe_pred(node)}, naslednik:{safe_succ(node)}, otec:{safe_father_of_first(node)}')
|
||||||
|
|
||||||
|
# Jsme prvnim synem
|
||||||
|
if safe_pred(node) is None:
|
||||||
|
if safe_succ(node) is None: # Jsme jedinym synem - upravime otce (pokud mame) a odpojime se
|
||||||
|
father = safe_father_of_first(node)
|
||||||
|
if father is not None:
|
||||||
|
father.first_child = None
|
||||||
|
father.save()
|
||||||
|
return
|
||||||
|
|
||||||
|
else: # mame bratra
|
||||||
|
swap_succ(node) # Staneme se neprvním synem, pokracujeme mimo if
|
||||||
|
|
||||||
|
# Jsme neprvním synem
|
||||||
|
prev = node.prev
|
||||||
|
prev.succ = node.succ
|
||||||
|
node.succ = None
|
||||||
|
node.save()
|
||||||
|
clear_root(node)
|
||||||
|
prev.save()
|
||||||
|
|
||||||
|
def clear_root(node):
|
||||||
|
node.root = None
|
||||||
|
node.save()
|
||||||
|
if node.first_child:
|
||||||
|
clear_root(node.first_child)
|
||||||
|
if node.succ:
|
||||||
|
clear_root(node.succ)
|
||||||
|
|
||||||
|
def set_root(node,root):
|
||||||
|
node.root = root
|
||||||
|
node.save()
|
||||||
|
if node.first_child:
|
||||||
|
clear_root(node.first_child)
|
||||||
|
if node.succ:
|
||||||
|
clear_root(node.succ)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.urls import path, include
|
from django.urls import path, include, re_path
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from . import views, export
|
from . import views, export
|
||||||
from .utils import org_required, resitel_required
|
from .utils import org_required, resitel_required
|
||||||
|
@ -20,6 +20,14 @@ urlpatterns = [
|
||||||
path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'),
|
path('cislo/<int:rocnik>.<str:cislo>/', views.CisloView.as_view(), name='seminar_cislo'),
|
||||||
path('problem/<int:pk>/', views.ProblemView.as_view(), name='seminar_problem'),
|
path('problem/<int:pk>/', views.ProblemView.as_view(), name='seminar_problem'),
|
||||||
path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='seminar_treenode'),
|
path('treenode/<int:pk>/', views.TreeNodeView.as_view(), name='seminar_treenode'),
|
||||||
|
path('treenode/<int:pk>/json/', views.TreeNodeJSONView.as_view(), name='seminar_treenode_json'),
|
||||||
|
path('treenode/text/<int:pk>/', views.TextWebView.as_view(), name='seminar_textnode_web'),
|
||||||
|
path('treenode/editor/pridat/<str:co>/<int:pk>/<str:kam>/', views.TreeNodePridatView.as_view(), name='treenode_pridat'),
|
||||||
|
path('treenode/editor/smazat/<int:pk>/', views.TreeNodeSmazatView.as_view(), name='treenode_smazat'),
|
||||||
|
path('treenode/editor/odvesitpryc/<int:pk>/', views.TreeNodeOdvesitPrycView.as_view(), name='treenode_odvesitpryc'),
|
||||||
|
path('treenode/editor/podvesit/<int:pk>/<str:kam>/', views.TreeNodePodvesitView.as_view(), name='treenode_podvesit'),
|
||||||
|
path('treenode/editor/prohodit/<int:pk>/', views.TreeNodeProhoditView.as_view(), name='treenode_prohodit'),
|
||||||
|
path('treenode/sirotcinec/', views.SirotcinecView.as_view(), name='seminar_treenode_sirotcinec'),
|
||||||
#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'),
|
#path('problem/(?P<pk>\d+)/(?P<prispevek>\d+)/', views.PrispevekView.as_view(), name='seminar_problem_prispevek'),
|
||||||
|
|
||||||
# Soustredeni
|
# Soustredeni
|
||||||
|
@ -50,7 +58,7 @@ urlpatterns = [
|
||||||
|
|
||||||
# Zadani
|
# Zadani
|
||||||
path('zadani/aktualni/', views.AktualniZadaniView.as_view(), name='seminar_aktualni_zadani'),
|
path('zadani/aktualni/', views.AktualniZadaniView.as_view(), name='seminar_aktualni_zadani'),
|
||||||
# path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'),
|
path('zadani/temata/', views.ZadaniTemataView, name='seminar_temata'),
|
||||||
#path('zadani/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'),
|
#path('zadani/vysledkova-listina/', views.ZadaniAktualniVysledkovkaView, name='seminar_vysledky'),
|
||||||
path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'),
|
path('stare-novinky/', views.StareNovinkyView.as_view(), name='stare_novinky'),
|
||||||
|
|
||||||
|
@ -149,6 +157,9 @@ urlpatterns = [
|
||||||
path('temp/add_solution', org_required(views.AddSolutionView.as_view()), name='seminar_vloz_reseni'),
|
path('temp/add_solution', org_required(views.AddSolutionView.as_view()), name='seminar_vloz_reseni'),
|
||||||
path('temp/nahraj_reseni', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'),
|
path('temp/nahraj_reseni', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'),
|
||||||
|
|
||||||
|
re_path(r'^temp/vue/.*$',views.VueTestView.as_view(),name='vue_test_view'),
|
||||||
|
path('temp/image_upload/', views.NahrajObrazekKTreeNoduView.as_view()),
|
||||||
|
|
||||||
path('', views.TitulniStranaView.as_view(), name='titulni_strana'),
|
path('', views.TitulniStranaView.as_view(), name='titulni_strana'),
|
||||||
path('jak-resit/', views.JakResitView.as_view(), name='jak-resit'),
|
path('jak-resit/', views.JakResitView.as_view(), name='jak-resit'),
|
||||||
|
|
||||||
|
|
|
@ -148,16 +148,12 @@ def resi_v_rocniku(rocnik, cislo=None):
|
||||||
|
|
||||||
if cislo is None:
|
if cislo is None:
|
||||||
# filtrujeme pouze podle ročníku
|
# filtrujeme pouze podle ročníku
|
||||||
letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik)
|
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
||||||
|
reseni__hodnoceni__cislo_body__rocnik=rocnik).distinct()
|
||||||
else: # filtrujeme podle ročníku i čísla
|
else: # filtrujeme podle ročníku i čísla
|
||||||
letosni_reseni = m.Reseni.objects.filter(hodnoceni__cislo_body__rocnik=rocnik,
|
return m.Resitel.objects.filter(rok_maturity__gte=rocnik.druhy_rok(),
|
||||||
hodnoceni__cislo_body__poradi__lte=cislo.poradi)
|
reseni__hodnoceni__cislo_body__rocnik=rocnik,
|
||||||
|
reseni__hodnoceni__cislo_body__poradi__lte=cislo.poradi).distinct()
|
||||||
# vygenerujeme queryset řešitelů, co letos něco poslali
|
|
||||||
letosni_resitele = m.Resitel.objects.none()
|
|
||||||
for reseni in letosni_reseni:
|
|
||||||
letosni_resitele = letosni_resitele | reseni.resitele.filter(rok_maturity__gte=rocnik.druhy_rok())
|
|
||||||
return letosni_resitele.distinct()
|
|
||||||
|
|
||||||
|
|
||||||
def aktivniResitele(cislo, pouze_letosni=False):
|
def aktivniResitele(cislo, pouze_letosni=False):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
from .views_all import *
|
from .views_all import *
|
||||||
from .autocomplete import *
|
from .autocomplete import *
|
||||||
|
from .views_rest import *
|
||||||
from .odevzdavatko import *
|
from .odevzdavatko import *
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# coding:utf-8
|
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render, redirect
|
from django.shortcuts import get_object_or_404, render, redirect
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
|
||||||
|
@ -16,13 +16,19 @@ from django.contrib.auth import views as auth_views
|
||||||
from django.contrib.auth.models import User, Permission
|
from django.contrib.auth.models import User, Permission
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.core import serializers
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.forms.models import model_to_dict
|
||||||
|
|
||||||
import seminar.models as s
|
import seminar.models as s
|
||||||
|
import seminar.models as m
|
||||||
from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci
|
from seminar.models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci
|
||||||
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
|
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
|
||||||
from seminar import utils, treelib
|
from seminar import utils, treelib
|
||||||
from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm
|
from seminar.forms import PrihlaskaForm, LoginForm, ProfileEditForm
|
||||||
import seminar.forms as f
|
import seminar.forms as f
|
||||||
|
import seminar.templatetags.treenodes as tnltt
|
||||||
|
import seminar.views.views_rest as vr
|
||||||
|
|
||||||
from datetime import timedelta, date, datetime, MAXYEAR
|
from datetime import timedelta, date, datetime, MAXYEAR
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -89,17 +95,142 @@ class ObalkovaniView(generic.ListView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
class TNLData(object):
|
class TNLData(object):
|
||||||
def __init__(self,anode):
|
def __init__(self,anode,parent=None, index=None):
|
||||||
self.node = anode
|
self.node = anode
|
||||||
|
self.sernode = vr.TreeNodeSerializer(anode)
|
||||||
self.children = []
|
self.children = []
|
||||||
|
self.parent = parent
|
||||||
|
self.tema_in_path = False
|
||||||
|
self.index = index
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
self.tema_in_path = parent.tema_in_path
|
||||||
|
if isinstance(anode, m.TemaVCisleNode):
|
||||||
|
self.tema_in_path = True
|
||||||
|
|
||||||
|
def add_edit_options(self):
|
||||||
|
self.deletable = tnltt.deletable(self)
|
||||||
|
self.editable_siblings = tnltt.editableSiblings(self)
|
||||||
|
self.editable_children = tnltt.editableChildren(self)
|
||||||
|
self.text_only_subtree = tnltt.textOnlySubtree(self)
|
||||||
|
self.can_podvesit_za = tnltt.canPodvesitZa(self)
|
||||||
|
self.can_podvesit_pred = tnltt.canPodvesitPred(self)
|
||||||
|
self.appendable_children = tnltt.appendableChildren(self)
|
||||||
|
print("appChld",self.appendable_children)
|
||||||
|
if self.parent:
|
||||||
|
self.appendable_siblings = tnltt.appendableChildren(self.parent)
|
||||||
|
else:
|
||||||
|
self.appendable_siblings = []
|
||||||
|
@classmethod
|
||||||
|
def public_above(cls, anode):
|
||||||
|
""" Returns output of verejne for closest Rocnik, Cislo or Problem above.
|
||||||
|
(All of them have method verejne.)"""
|
||||||
|
parent = anode # chceme začít už od konkrétního node včetně
|
||||||
|
while True:
|
||||||
|
rocnik = isinstance(parent, s.RocnikNode)
|
||||||
|
cislo = isinstance(parent, s.CisloNode)
|
||||||
|
uloha = (isinstance(parent, s.UlohaVzorakNode) or
|
||||||
|
isinstance(parent, s.UlohaZadaniNode))
|
||||||
|
tema = isinstance(parent, s.TemaVCisleNode)
|
||||||
|
|
||||||
|
if (rocnik or cislo or uloha or tema) or parent==None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
parent = treelib.get_parent(parent)
|
||||||
|
if rocnik:
|
||||||
|
return parent.rocnik.verejne()
|
||||||
|
elif cislo:
|
||||||
|
return parent.cislo.verejne()
|
||||||
|
elif uloha:
|
||||||
|
return parent.uloha.verejne()
|
||||||
|
elif tema:
|
||||||
|
return parent.tema.verejne()
|
||||||
|
elif None:
|
||||||
|
print("Existuje TreeNode, který není pod číslem, ročníkem, úlohou"
|
||||||
|
"ani tématem. {}".format(anode))
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all_public_children(cls, anode):
|
||||||
|
for ch in treelib.all_children(anode):
|
||||||
|
if TNLData.public_above(ch):
|
||||||
|
yield ch
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_treenode(cls, anode, user, parent=None, index=None):
|
||||||
|
if TNLData.public_above(anode) or user.has_perm('auth.org'):
|
||||||
|
out = cls(anode,parent,index)
|
||||||
|
else:
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
if user.has_perm('auth.org'):
|
||||||
|
enum_children = enumerate(treelib.all_children(anode))
|
||||||
|
else:
|
||||||
|
enum_children = enumerate(TNLData.all_public_children(anode))
|
||||||
|
|
||||||
|
for (idx,ch) in enum_children:
|
||||||
|
outitem = cls.from_treenode(ch, user, out, idx)
|
||||||
|
out.children.append(outitem)
|
||||||
|
out.add_edit_options()
|
||||||
|
return out
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_tnldata_list(cls, tnllist):
|
||||||
|
"""Vyrobíme virtuální TNL, který nemá obsah, ale má za potomky všechna zadaná TNLData"""
|
||||||
|
result = cls(None)
|
||||||
|
for idx, tnl in enumerate(tnllist):
|
||||||
|
result.children.append(tnl)
|
||||||
|
tnl.parent = result
|
||||||
|
tnl.index = idx
|
||||||
|
result.add_edit_options()
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def filter_treenode(cls, treenode, predicate):
|
||||||
|
tnll = cls._filter_treenode_recursive(treenode, predicate) # TreeNodeList List :-)
|
||||||
|
return TNLData.from_tnldata_list(tnll)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _filter_treenode_recursive(cls, treenode, predicate):
|
||||||
|
if predicate(treenode):
|
||||||
|
return [cls.from_treenode(treenode)]
|
||||||
|
else:
|
||||||
|
found = []
|
||||||
|
for tn in all_children(treenode):
|
||||||
|
result = cls.filter_treenode(tn, predicate)
|
||||||
|
# Result by v tuhle chvíli měl být seznam TNLDat odpovídající treenodům, jež matchnuly predikát.
|
||||||
|
for tnl in result:
|
||||||
|
found.append(tnl)
|
||||||
|
return found
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
#self.node = anode
|
||||||
|
#self.children = []
|
||||||
|
#self.parent = parent
|
||||||
|
#self.tema_in_path = False
|
||||||
|
#self.index = index
|
||||||
|
out = {}
|
||||||
|
out['node'] = self.sernode.data
|
||||||
|
out['children'] = [n.to_json() for n in self.children]
|
||||||
|
out['tema_in_path'] = self.tema_in_path
|
||||||
|
out['index'] = self.index
|
||||||
|
out['deletable'] = self.deletable
|
||||||
|
out['editable_siblings'] = self.editable_siblings
|
||||||
|
out['editable_children'] = self.editable_children
|
||||||
|
out['text_only_subtree'] = self.text_only_subtree
|
||||||
|
out['can_podvesit_za'] = self.can_podvesit_za
|
||||||
|
out['can_podvesit_pod'] = self.can_podvesit_pred
|
||||||
|
out['appendable_children'] = self.appendable_children
|
||||||
|
out['appendable_siblings'] = self.appendable_siblings
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def treenode_strom_na_seznamy(node):
|
|
||||||
out = TNLData(node)
|
def __repr__(self):
|
||||||
for ch in treelib.all_children(node):
|
return("TNL({})".format(self.node))
|
||||||
outitem = treenode_strom_na_seznamy(ch)
|
|
||||||
out.children.append(outitem)
|
|
||||||
return out
|
|
||||||
|
|
||||||
class TreeNodeView(generic.DetailView):
|
class TreeNodeView(generic.DetailView):
|
||||||
model = s.TreeNode
|
model = s.TreeNode
|
||||||
|
@ -107,22 +238,181 @@ class TreeNodeView(generic.DetailView):
|
||||||
|
|
||||||
def get_context_data(self,**kwargs):
|
def get_context_data(self,**kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['tnldata'] = treenode_strom_na_seznamy(self.object)
|
context['tnldata'] = TNLData.from_treenode(self.object,self.request.user)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
# TODO Co chceme vlastně zobrazovat na této stránce? Zatím je zde aktuální číslo, ale může tu být cokoli jiného...
|
|
||||||
class AktualniZadaniView(TreeNodeView):
|
|
||||||
def get_object(self):
|
|
||||||
nastaveni = get_object_or_404(Nastaveni)
|
|
||||||
return nastaveni.aktualni_cislo.cislonode
|
|
||||||
|
|
||||||
def get_context_data(self,**kwargs):
|
class TreeNodeJSONView(generic.DetailView):
|
||||||
nastaveni = get_object_or_404(Nastaveni)
|
model = s.TreeNode
|
||||||
|
|
||||||
|
def get(self,request,*args, **kwargs):
|
||||||
|
self.object = self.get_object()
|
||||||
|
data = TNLData.from_treenode(self.object,self.request.user).to_json()
|
||||||
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TreeNodePridatView(generic.View):
|
||||||
|
type_from_str = {
|
||||||
|
'rocnikNode': m.RocnikNode,
|
||||||
|
'cisloNode': m.CisloNode,
|
||||||
|
'castNode': m.CastNode,
|
||||||
|
'textNode': m.TextNode,
|
||||||
|
'temaVCisleNode': m.TemaVCisleNode,
|
||||||
|
'reseniNode': m.ReseniNode,
|
||||||
|
'ulohaZadaniNode': m.UlohaZadaniNode,
|
||||||
|
'ulohaVzorakNode': m.UlohaVzorakNode,
|
||||||
|
'pohadkaNode': m.PohadkaNode,
|
||||||
|
'orgText': m.OrgTextNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
######## FIXME: ROZEPSANE, NEFUNGUJE, DOPSAT !!!!!! ###########
|
||||||
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
||||||
|
kam = self.kwargs['kam']
|
||||||
|
co = self.kwargs['co']
|
||||||
|
typ = self.type_from_str[co]
|
||||||
|
|
||||||
|
raise NotImplementedError('Neni to dopsane, dopis to!')
|
||||||
|
|
||||||
|
if kam not in ('pred','syn','za'):
|
||||||
|
raise ValidationError('Přidat lze pouze před nebo za node nebo jako syna')
|
||||||
|
|
||||||
|
if co == m.TextNode:
|
||||||
|
new_obj = m.Text()
|
||||||
|
new_obj.save()
|
||||||
|
elif co == m.CastNode:
|
||||||
|
new_obj = m.CastNode()
|
||||||
|
new_obj.nadpis = request.POST.get('pridat-castNode-{}-{}'.format(node.id,kam))
|
||||||
|
new_obj.save()
|
||||||
|
elif co == m.ReseniNode:
|
||||||
|
new_obj = m
|
||||||
|
pass
|
||||||
|
elif co == m.UlohaZadaniNode:
|
||||||
|
pass
|
||||||
|
elif co == m.UlohaReseniNode:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
new_obj = None
|
||||||
|
|
||||||
|
|
||||||
|
if kam == 'pred':
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if kam == 'syn':
|
||||||
|
if typ == m.TextNode:
|
||||||
|
text_obj = m.Text()
|
||||||
|
text_obj.save()
|
||||||
|
node = treelib.create_child(node,typ,text=text_obj)
|
||||||
|
else:
|
||||||
|
node = treelib.create_child(node,typ)
|
||||||
|
if kam == 'za':
|
||||||
|
if typ == m.TextNode:
|
||||||
|
text_obj = m.Text()
|
||||||
|
text_obj.save()
|
||||||
|
node = treelib.create_node_after(node,typ,text=text_obj)
|
||||||
|
else:
|
||||||
|
node = treelib.create_node_after(node,typ)
|
||||||
|
|
||||||
|
return redirect(node.get_admin_url())
|
||||||
|
|
||||||
|
|
||||||
|
class TreeNodeSmazatView(generic.base.View):
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
||||||
|
if node.first_child:
|
||||||
|
raise NotImplementedError('Mazání TreeNode se syny není zatím podporováno!')
|
||||||
|
treelib.disconnect_node(node)
|
||||||
|
node.delete()
|
||||||
|
return redirect(request.headers.get('referer'))
|
||||||
|
|
||||||
|
class TreeNodeOdvesitPrycView(generic.base.View):
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
||||||
|
treelib.disconnect_node(node)
|
||||||
|
node.root = None
|
||||||
|
node.save()
|
||||||
|
return redirect(request.headers.get('referer'))
|
||||||
|
|
||||||
|
|
||||||
|
class TreeNodePodvesitView(generic.base.View):
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
||||||
|
kam = self.kwargs['kam']
|
||||||
|
if kam == 'pred':
|
||||||
|
treelib.lower_node(node)
|
||||||
|
elif kam == 'za':
|
||||||
|
raise NotImplementedError('Podvěsit za není zatím podporováno')
|
||||||
|
return redirect(request.headers.get('referer'))
|
||||||
|
|
||||||
|
class TreeNodeProhoditView(generic.base.View):
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
node = s.TreeNode.objects.get(pk=self.kwargs['pk'])
|
||||||
|
treelib.swap_succ(node)
|
||||||
|
return redirect(request.headers.get('referer'))
|
||||||
|
#FIXME ve formulari predat puvodni url a vratit redirect na ni
|
||||||
|
|
||||||
|
class SirotcinecView(generic.ListView):
|
||||||
|
model = s.TreeNode
|
||||||
|
template_name = 'seminar/orphanage.html'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return s.TreeNode.objects.not_instance_of(s.RocnikNode).filter(root=None,prev=None,succ=None,father_of_first=None)
|
||||||
|
|
||||||
|
# FIXME pouzit Django REST Framework
|
||||||
|
class TextWebView(generic.DetailView):
|
||||||
|
model = s.Text
|
||||||
|
|
||||||
|
def get(self,request,*args, **kwargs):
|
||||||
|
self.object = self.get_object()
|
||||||
|
return JsonResponse(model_to_dict(self.object,exclude='do_cisla'))
|
||||||
|
|
||||||
|
|
||||||
|
class ProblemView(generic.DetailView):
|
||||||
|
model = s.Problem
|
||||||
|
# Zkopírujeme template_name od TreeNodeView, protože jsme prakticky jen trošku upravený TreeNodeView
|
||||||
|
template_name = TreeNodeView.template_name
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
verejne = nastaveni.aktualni_cislo.verejne()
|
user = self.request.user
|
||||||
context['verejne'] = verejne
|
# Teď potřebujeme doplnit tnldata do kontextu.
|
||||||
|
# Ošklivý type switch, hezčí by bylo udělat to polymorfni. FIXME.
|
||||||
|
if False:
|
||||||
|
# Hezčí formátování zbytku :-P
|
||||||
|
pass
|
||||||
|
elif isinstance(self.object, s.Clanek) or isinstance(self.object, s.Konfera):
|
||||||
|
# Tyhle Problémy mají ŘešeníNode
|
||||||
|
context['tnldata'] = TNLData.from_treenode(self.object.reseninode,user)
|
||||||
|
elif isinstance(self.object, s.Uloha):
|
||||||
|
# FIXME: Teď vždycky zobrazujeme i vzorák! Možná by bylo hezčí/lepší mít to stejně jako pro Téma: procházet jen dosažitelné z Ročníku / čísla / whatever
|
||||||
|
tnl_zadani = TNLData.from_treenode(self.object.ulohazadaninode,user)
|
||||||
|
tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode,user)
|
||||||
|
context['tnldata'] = TNLData.from_tnldata_list([tnl_zadani, tnl_vzorak])
|
||||||
|
elif isinstance(self.object, s.Tema):
|
||||||
|
rocniknode = self.object.rocnik.rocniknode
|
||||||
|
context['tnldata'] = TNLData.filter_treenode(rocniknode, lambda x: isinstance(x, s.TemaVCisleNode))
|
||||||
|
else:
|
||||||
|
raise ValueError("Obecný problém nejde zobrazit.")
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class AktualniZadaniView(generic.TemplateView):
|
||||||
|
template_name = 'seminar/treenode.html'
|
||||||
|
|
||||||
|
# TODO Co chceme vlastně zobrazovat na této stránce? Zatím je zde aktuální číslo, ale může tu být cokoli jiného...
|
||||||
|
#class AktualniZadaniView(TreeNodeView):
|
||||||
|
# def get_object(self):
|
||||||
|
# nastaveni = get_object_or_404(Nastaveni)
|
||||||
|
# return nastaveni.aktualni_cislo.cislonode
|
||||||
|
#
|
||||||
|
# def get_context_data(self,**kwargs):
|
||||||
|
# nastaveni = get_object_or_404(Nastaveni)
|
||||||
|
# context = super().get_context_data(**kwargs)
|
||||||
|
# verejne = nastaveni.aktualni_cislo.verejne()
|
||||||
|
# context['verejne'] = verejne
|
||||||
|
# return context
|
||||||
|
|
||||||
#def AktualniZadaniView(request):
|
#def AktualniZadaniView(request):
|
||||||
# nastaveni = get_object_or_404(Nastaveni)
|
# nastaveni = get_object_or_404(Nastaveni)
|
||||||
# verejne = nastaveni.aktualni_cislo.verejne()
|
# verejne = nastaveni.aktualni_cislo.verejne()
|
||||||
|
@ -138,7 +428,19 @@ class AktualniZadaniView(TreeNodeView):
|
||||||
# },
|
# },
|
||||||
# )
|
# )
|
||||||
#
|
#
|
||||||
#def ZadaniTemataView(request):
|
def ZadaniTemataView(request):
|
||||||
|
nastaveni = get_object_or_404(Nastaveni)
|
||||||
|
verejne = nastaveni.aktualni_cislo.verejne()
|
||||||
|
akt_rocnik = nastaveni.aktualni_cislo.rocnik
|
||||||
|
temata = s.Tema.objects.filter(rocnik=akt_rocnik, stav='zadany')
|
||||||
|
return render(request, 'seminar/tematka/rozcestnik.html',
|
||||||
|
{
|
||||||
|
'tematka': temata,
|
||||||
|
'verejne': verejne,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# nastaveni = get_object_or_404(Nastaveni)
|
# nastaveni = get_object_or_404(Nastaveni)
|
||||||
# temata = verejna_temata(nastaveni.aktualni_rocnik)
|
# temata = verejna_temata(nastaveni.aktualni_rocnik)
|
||||||
# for t in temata:
|
# for t in temata:
|
||||||
|
@ -1318,6 +1620,32 @@ class PasswordChangeView(auth_views.PasswordChangeView):
|
||||||
#template_name = 'seminar/password_change.html'
|
#template_name = 'seminar/password_change.html'
|
||||||
success_url = reverse_lazy('titulni_strana')
|
success_url = reverse_lazy('titulni_strana')
|
||||||
|
|
||||||
|
class VueTestView(generic.TemplateView):
|
||||||
|
template_name = 'seminar/vuetest.html'
|
||||||
|
|
||||||
|
class NahrajObrazekKTreeNoduView(LoginRequiredMixin, CreateView):
|
||||||
|
model = s.Obrazek
|
||||||
|
form_class = f.NahrajObrazekKTreeNoduForm
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
initial = super().get_initial()
|
||||||
|
initial['na_web'] = self.request.FILES['upload']
|
||||||
|
return initial
|
||||||
|
|
||||||
|
|
||||||
|
def form_valid(self,form):
|
||||||
|
print(self.request.headers)
|
||||||
|
print(self.request.headers['Textid'])
|
||||||
|
print(form.instance)
|
||||||
|
print(form)
|
||||||
|
self.object = form.save(commit=False)
|
||||||
|
print(self.object.na_web)
|
||||||
|
self.object.text = m.Text.objects.get(pk=int(self.request.headers['Textid']))
|
||||||
|
self.object.save()
|
||||||
|
|
||||||
|
return JsonResponse({"url":self.object.na_web.url})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Jen hloupé rozhazovátko
|
# Jen hloupé rozhazovátko
|
||||||
def profilView(request):
|
def profilView(request):
|
||||||
|
|
162
seminar/views/views_rest.py
Normal file
162
seminar/views/views_rest.py
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from rest_polymorphic.serializers import PolymorphicSerializer
|
||||||
|
|
||||||
|
import seminar.models as m
|
||||||
|
from seminar import treelib
|
||||||
|
|
||||||
|
DEFAULT_NODE_DEPTH = 2
|
||||||
|
|
||||||
|
class TextSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.Text
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UlohaVzorakNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.UlohaVzorakNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class UlohaZadaniNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.UlohaZadaniNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class RocnikNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.RocnikNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class CisloNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.CisloNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class MezicisloNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.MezicisloNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class TemaVCisleNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.TemaVCisleNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class OrgTextNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.OrgTextNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class PohadkaNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.PohadkaNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class TextNodeSerializer(serializers.ModelSerializer):
|
||||||
|
text = TextSerializer()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = m.TextNode
|
||||||
|
fields = ('id','text','polymorphic_ctype')
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class TextNodeWriteSerializer(serializers.ModelSerializer):
|
||||||
|
text = TextSerializer()
|
||||||
|
|
||||||
|
def update(self,node,validated_data):
|
||||||
|
node.text.na_web = validated_data.get('text').get('na_web')
|
||||||
|
node.text.save()
|
||||||
|
return node
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = m.TextNode
|
||||||
|
fields = ('id','text')
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class TextNodeCreateSerializer(serializers.ModelSerializer):
|
||||||
|
text = TextSerializer()
|
||||||
|
refnode = serializers.CharField()
|
||||||
|
where = serializers.CharField()
|
||||||
|
|
||||||
|
def create(self,validated_data):
|
||||||
|
temp_text = validated_data.pop('text')
|
||||||
|
where = validated_data.pop('where')
|
||||||
|
refnode_id = validated_data.pop('refnode')
|
||||||
|
refnode = m.TreeNode.objects.get(pk=refnode_id)
|
||||||
|
text = m.Text.objects.create(**temp_text)
|
||||||
|
if where == 'syn':
|
||||||
|
node = treelib.create_child(refnode,m.TextNode,text=text)
|
||||||
|
elif where == 'za':
|
||||||
|
node = treelib.create_node_after(refnode,m.TextNode,text=text)
|
||||||
|
elif where == 'pred':
|
||||||
|
node = treelib.create_node_before(refnode,m.TextNode,text=text)
|
||||||
|
node.where = None
|
||||||
|
node.refnode = None
|
||||||
|
return node
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = m.TextNode
|
||||||
|
fields = ('text','where','refnode')
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class CastNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.CastNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class CastNodeCreateSerializer(serializers.ModelSerializer):
|
||||||
|
refnode = serializers.CharField()
|
||||||
|
where = serializers.CharField()
|
||||||
|
|
||||||
|
def create(self,validated_data):
|
||||||
|
temp_nadpis = validated_data.pop('nadpis')
|
||||||
|
where = validated_data.pop('where')
|
||||||
|
refnode_id = validated_data.pop('refnode')
|
||||||
|
refnode = m.TreeNode.objects.get(pk=refnode_id)
|
||||||
|
if where == 'syn':
|
||||||
|
node = treelib.create_child(refnode,m.CastNode,nadpis=temp_nadpis)
|
||||||
|
elif where == 'za':
|
||||||
|
node = treelib.create_node_after(refnode,m.CastNode,nadpis=temp_nadpis)
|
||||||
|
elif where == 'pred':
|
||||||
|
node = treelib.create_node_before(refnode,m.CastNode,nadpis=temp_nadpis)
|
||||||
|
node.where = None
|
||||||
|
node.refnode = None
|
||||||
|
return node
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = m.CastNode
|
||||||
|
fields = ('nadpis','where','refnode')
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
class ReseniNodeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = m.ReseniNode
|
||||||
|
fields = '__all__'
|
||||||
|
depth = DEFAULT_NODE_DEPTH
|
||||||
|
|
||||||
|
|
||||||
|
class TreeNodeSerializer(PolymorphicSerializer):
|
||||||
|
model_serializer_mapping = {
|
||||||
|
m.RocnikNode: RocnikNodeSerializer,
|
||||||
|
m.CisloNode: CisloNodeSerializer,
|
||||||
|
m.MezicisloNode: MezicisloNodeSerializer,
|
||||||
|
m.TemaVCisleNode: TemaVCisleNodeSerializer,
|
||||||
|
m.OrgTextNode: OrgTextNodeSerializer,
|
||||||
|
m.UlohaZadaniNode: UlohaZadaniNodeSerializer,
|
||||||
|
m.UlohaVzorakNode: UlohaVzorakNodeSerializer,
|
||||||
|
m.PohadkaNode: PohadkaNodeSerializer,
|
||||||
|
m.TextNode: TextNodeSerializer,
|
||||||
|
m.CastNode: CastNodeSerializer,
|
||||||
|
m.ReseniNode: ReseniNodeSerializer,
|
||||||
|
}
|
||||||
|
|
96
seminar/viewsets.py
Normal file
96
seminar/viewsets.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
from rest_framework import viewsets,filters
|
||||||
|
from rest_framework.permissions import BasePermission, AllowAny
|
||||||
|
from . import models as m
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
from seminar.permissions import AllowWrite
|
||||||
|
|
||||||
|
class PermissionMixin(object):
|
||||||
|
""" Redefines get_permissions so that only organizers can make changes. """
|
||||||
|
|
||||||
|
def get_permissions(self):
|
||||||
|
permission_classes = []
|
||||||
|
print("get_permissions have been called.")
|
||||||
|
if self.action in ["create", "update", "partial_update", "destroy"]:
|
||||||
|
permission_classes = [AllowWrite] # speciální permission na zápis - orgové
|
||||||
|
else:
|
||||||
|
permission_classes = [AllowAny]
|
||||||
|
# návštěvník nemusí být zalogován, aby si prohlížel obsah
|
||||||
|
return [permission() for permission in permission_classes]
|
||||||
|
|
||||||
|
class ReadWriteSerializerMixin(object):
|
||||||
|
"""
|
||||||
|
Overrides get_serializer_class to choose the read serializer
|
||||||
|
for GET requests and the write serializer for POST requests.
|
||||||
|
|
||||||
|
Set read_serializer_class and write_serializer_class attributes on a
|
||||||
|
viewset.
|
||||||
|
"""
|
||||||
|
|
||||||
|
read_serializer_class = None
|
||||||
|
create_serializer_class = None
|
||||||
|
write_serializer_class = None
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == "create":
|
||||||
|
return self.get_create_serializer_class()
|
||||||
|
if self.action in ["update", "partial_update", "destroy"]:
|
||||||
|
return self.get_write_serializer_class()
|
||||||
|
return self.get_read_serializer_class()
|
||||||
|
|
||||||
|
def get_read_serializer_class(self):
|
||||||
|
assert self.read_serializer_class is not None, (
|
||||||
|
"'%s' should either include a `read_serializer_class` attribute,"
|
||||||
|
"or override the `get_read_serializer_class()` method."
|
||||||
|
% self.__class__.__name__
|
||||||
|
)
|
||||||
|
return self.read_serializer_class
|
||||||
|
|
||||||
|
def get_write_serializer_class(self):
|
||||||
|
assert self.write_serializer_class is not None, (
|
||||||
|
"'%s' should either include a `write_serializer_class` attribute,"
|
||||||
|
"or override the `get_write_serializer_class()` method."
|
||||||
|
% self.__class__.__name__
|
||||||
|
)
|
||||||
|
return self.write_serializer_class
|
||||||
|
|
||||||
|
def get_create_serializer_class(self):
|
||||||
|
assert self.create_serializer_class is not None, (
|
||||||
|
"'%s' should either include a `create_serializer_class` attribute,"
|
||||||
|
"or override the `get_create_serializer_class()` method."
|
||||||
|
% self.__class__.__name__
|
||||||
|
)
|
||||||
|
return self.create_serializer_class
|
||||||
|
|
||||||
|
class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet):
|
||||||
|
queryset = m.UlohaVzorakNode.objects.all()
|
||||||
|
serializer_class = views.UlohaVzorakNodeSerializer
|
||||||
|
|
||||||
|
class TextViewSet(PermissionMixin, viewsets.ModelViewSet):
|
||||||
|
queryset = m.Text.objects.all()
|
||||||
|
serializer_class = views.TextSerializer
|
||||||
|
|
||||||
|
class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet):
|
||||||
|
queryset = m.TextNode.objects.all()
|
||||||
|
read_serializer_class = views.TextNodeSerializer
|
||||||
|
write_serializer_class = views.TextNodeWriteSerializer
|
||||||
|
create_serializer_class = views.TextNodeCreateSerializer
|
||||||
|
|
||||||
|
class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet):
|
||||||
|
queryset = m.CastNode.objects.all()
|
||||||
|
read_serializer_class = views.CastNodeSerializer
|
||||||
|
write_serializer_class = views.CastNodeSerializer
|
||||||
|
create_serializer_class = views.CastNodeCreateSerializer
|
||||||
|
|
||||||
|
class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet):
|
||||||
|
serializer_class = views.UlohaVzorakNodeSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = m.UlohaVzorakNode.objects.all()
|
||||||
|
nazev = self.request.query_params.get('nazev',None)
|
||||||
|
if nazev is not None:
|
||||||
|
queryset = queryset.filter(nazev__contains=nazev)
|
||||||
|
if self.request.user.has_perm('auth.org'):
|
||||||
|
return queryset
|
||||||
|
else: # pro neorgy jen zveřejněné vzoráky
|
||||||
|
return queryset.filter(uloha__cislo_reseni__verejne_db=True)
|
22
vue_frontend/.gitignore
vendored
Normal file
22
vue_frontend/.gitignore
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
5
vue_frontend/babel.config.js
Normal file
5
vue_frontend/babel.config.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
48
vue_frontend/package.json
Normal file
48
vue_frontend/package.json
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"name": "vue_frontend",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ckeditor/ckeditor5-upload": "^23.0.0",
|
||||||
|
"@ckeditor/ckeditor5-vue": "^1.0.1",
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"ckeditor5-build-classic-simple-upload-adapter-image-resize": "^1.0.4",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-router": "^3.4.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "~4.4.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.4.0",
|
||||||
|
"@vue/cli-service": "^4.5.6",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"vue-template-compiler": "^2.6.11",
|
||||||
|
"webpack-bundle-tracker": "0.4.3"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
},
|
||||||
|
"rules": {}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not dead"
|
||||||
|
]
|
||||||
|
}
|
7
vue_frontend/src/App.vue
Normal file
7
vue_frontend/src/App.vue
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<template>
|
||||||
|
<router-view id="app"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default { name: 'app' }
|
||||||
|
</script>
|
50
vue_frontend/src/components/AddNewNode.vue
Normal file
50
vue_frontend/src/components/AddNewNode.vue
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<template>
|
||||||
|
<div class="addnewnode">
|
||||||
|
<button v-if="types.includes('castNode')" v-on:click="selected='castNode'" :disabled="selected && selected !== 'castNode'">Část</button>
|
||||||
|
<button v-if="types.includes('textNode')" v-on:click="selected='textNode'" :disabled="selected && selected !== 'textNode'">Text</button>
|
||||||
|
<button v-if="types.includes('reseniNode')" v-on:click="selected='reseniNode'" :disabled="selected && selected !== 'reseniNode'">Řešení</button>
|
||||||
|
<button v-if="types.includes('ulohaZadaniNode')" v-on:click="selected='ulohaZadaniNode'" :disabled="selected && selected !== 'ulohaZadaniNode'">Zadání úlohy</button>
|
||||||
|
<button v-if="types.includes('ulohaVzorakNode')" v-on:click="selected='ulohaVzorakNode'" :disabled="selected && selected !== 'ulohaVzorakNode'">Vzorák</button>
|
||||||
|
<div v-if="selected">
|
||||||
|
<component :is='selected' :item='null' :where="where" :refnode="refnode" create></component>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import castNode from './CastNode.vue'
|
||||||
|
import textNode from './TextNode.vue'
|
||||||
|
import ulohaZadaniNode from './UlohaZadaniNode.vue'
|
||||||
|
import ulohaVzorakNode from './UlohaVzorakNode.vue'
|
||||||
|
//import reseniNode from './UlohaVzorakNode.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AddNewNode',
|
||||||
|
props: {
|
||||||
|
types: Array,
|
||||||
|
where: String,
|
||||||
|
refnode: Object,
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
selected: null,
|
||||||
|
}),
|
||||||
|
components: {
|
||||||
|
castNode,
|
||||||
|
textNode,
|
||||||
|
ulohaZadaniNode,
|
||||||
|
ulohaVzorakNode,
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
this.$root.$on('dataUpdated',(arg) => {
|
||||||
|
this.selected = null;
|
||||||
|
console.log('dataUpdated'+arg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.addnewnode {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
</style>
|
86
vue_frontend/src/components/CastNode.vue
Normal file
86
vue_frontend/src/components/CastNode.vue
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<template>
|
||||||
|
<div class="castnode">
|
||||||
|
<!--pre>CastNode {{item}} {{typeof(item)}}</pre-->
|
||||||
|
<div v-if="editorShow">
|
||||||
|
<input type="text" v-model="currentText" />
|
||||||
|
<button v-on:click="saveText">Uložit</button>
|
||||||
|
<button v-on:click="currentText = originalText;editorShow=!editorShow;">Zahodit úpravy</button>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<h4>{{ currentText }} </h4> <button v-if="editorMode" v-on:click="editorShow=!editorShow">Upravit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CastNode',
|
||||||
|
data: () => ({
|
||||||
|
editorShow: false,
|
||||||
|
currentText: "",
|
||||||
|
originalText: "",
|
||||||
|
}),
|
||||||
|
props: {
|
||||||
|
item: Object,
|
||||||
|
editorShow: Boolean,
|
||||||
|
create: Boolean,
|
||||||
|
where: String,
|
||||||
|
refnode: Object
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
if (this.create){
|
||||||
|
this.currentText = "";
|
||||||
|
this.originalText = "";
|
||||||
|
this.editorShow = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.currentText = this.item.node.nadpis;
|
||||||
|
this.originalText = this.item.node.nadpis;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.getText();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
saveText: function() {
|
||||||
|
console.log("Saving cast");
|
||||||
|
console.log(this.currentText);
|
||||||
|
if (this.create){
|
||||||
|
console.log(this.refnode);
|
||||||
|
console.log(this.where);
|
||||||
|
axios.post('/api/castnode/',{
|
||||||
|
'nadpis': this.currentText,
|
||||||
|
'refnode': this.refnode.id,
|
||||||
|
'where': this.where
|
||||||
|
}).then(response => {
|
||||||
|
this.originalText = response.data.nadpis;
|
||||||
|
this.$root.$emit('updateData',"castNode create update");
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(e);
|
||||||
|
this.errors.push(e);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
axios.put('/api/castnode/'+this.item.node.id+'/',{
|
||||||
|
'nadpis': this.currentText,
|
||||||
|
'id': this.item.node.id
|
||||||
|
}).then(response => {
|
||||||
|
this.originalText = response.data.nadpis;
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(e);
|
||||||
|
this.errors.push(e)
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editorShow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
19
vue_frontend/src/components/CisloNode.vue
Normal file
19
vue_frontend/src/components/CisloNode.vue
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<template>
|
||||||
|
<div class="cislonode">
|
||||||
|
<!--pre>CisloNode {{item}} {{typeof(item)}}</pre-->
|
||||||
|
<h1>{{ item.node.cislo.poradi }}. číslo</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'CisloNode',
|
||||||
|
props: {
|
||||||
|
item: Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
21
vue_frontend/src/components/RocnikNode.vue
Normal file
21
vue_frontend/src/components/RocnikNode.vue
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="rocniknode">
|
||||||
|
<!--pre>RocnikNode {{item}} {{typeof(item)}}</pre-->
|
||||||
|
<h1>Ročník {{ item.node.rocnik.rocnik }} ({{ item.node.rocnik.prvni_rok }}/{{item.node.rocnik.prvni_rok+1 }})</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'RocnikNode',
|
||||||
|
props: {
|
||||||
|
item: Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
19
vue_frontend/src/components/TemaVCisleNode.vue
Normal file
19
vue_frontend/src/components/TemaVCisleNode.vue
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<template>
|
||||||
|
<div class="temavcislenode">
|
||||||
|
<!--pre>TemaVCisleNode {{item}} {{typeof(item)}}</pre-->
|
||||||
|
<h2>Téma {{ item.node.tema.kod }}: {{ item.node.tema.nazev }}</h2>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TemaVCisleNode',
|
||||||
|
props: {
|
||||||
|
item: Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
174
vue_frontend/src/components/TextNode.vue
Normal file
174
vue_frontend/src/components/TextNode.vue
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="loading" class="loading">
|
||||||
|
<p>Loading...</p>
|
||||||
|
</div>
|
||||||
|
<div v-else class="textnode">
|
||||||
|
<!--pre>TextNode {{item}} {{typeof(item)}}</pre-->
|
||||||
|
<template v-if="editorShow">
|
||||||
|
|
||||||
|
<div v-if="plainEditShow">
|
||||||
|
<textarea id="textarea" v-model="currentText" rows="8" cols="50"></textarea>
|
||||||
|
<br>
|
||||||
|
<button v-on:click="plainEditShow=!plainEditShow">Editovat v editoru</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<component v-bind:is="editorComponent" :editor="editor" v-model="currentText" :config="editorConfig"></component>
|
||||||
|
<button v-on:click="plainEditShow=!plainEditShow">Editovat HTML</button>
|
||||||
|
</div>
|
||||||
|
<button v-on:click="saveText">Uložit</button>
|
||||||
|
<button v-on:click="currentText = originalText;editorShow=!editorShow;">Zahodit úpravy</button>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else v-bind:class="changedObject">
|
||||||
|
<p v-html="currentText"></p>
|
||||||
|
<button v-if="editorMode" v-on:click="editorShow=!editorShow">Upravit</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
//import ClassicEditor from '@ckeditor/ckeditor5-build-classic'
|
||||||
|
import ClassicEditor from 'ckeditor5-build-classic-simple-upload-adapter-image-resize';
|
||||||
|
import CKEditor from '@ckeditor/ckeditor5-vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TextNode',
|
||||||
|
data: () => ({
|
||||||
|
loading: false,
|
||||||
|
editor: ClassicEditor,
|
||||||
|
editorData: '<p>Content of the editor.</p>',
|
||||||
|
editorConfig: {
|
||||||
|
extraPlugins: ['SimpleUploadAdapter'],
|
||||||
|
simpleUpload: {
|
||||||
|
uploadUrl: "/temp/image_upload/",
|
||||||
|
headers: {},
|
||||||
|
withCredentials: true
|
||||||
|
}
|
||||||
|
// The configuration of the editor.
|
||||||
|
},
|
||||||
|
editorShow: false,
|
||||||
|
plainEditShow: false,
|
||||||
|
editorComponent: CKEditor.component,
|
||||||
|
currentText: "",// this.item.node.text.na_web,
|
||||||
|
originalText: "",// this.item.node.text.na_web,
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
changedObject: function () {
|
||||||
|
//console.log(this.currentText);
|
||||||
|
//console.log(this.originalText);
|
||||||
|
return {
|
||||||
|
changed: this.currentText !== this.originalText,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
textId: function () {
|
||||||
|
console.log(this.create);
|
||||||
|
console.log(this.node.text.id);
|
||||||
|
if (this.create){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.node.text.id;
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
item: Object,
|
||||||
|
editorShow: Boolean,
|
||||||
|
editorMode: Boolean,
|
||||||
|
create: Boolean,
|
||||||
|
where: String,
|
||||||
|
refnode: Object
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
//console.log("mounted");
|
||||||
|
this.editorConfig.simpleUpload.headers['X-CSRFToken'] = this.getCookie('csrftoken');
|
||||||
|
axios.defaults.headers.common['X-CSRFToken'] = this.getCookie('csrftoken');
|
||||||
|
if (this.create){
|
||||||
|
this.currentText = "";
|
||||||
|
this.originalText = "";
|
||||||
|
this.editorShow = true;
|
||||||
|
} else {
|
||||||
|
this.currentText = this.item.node.text.na_web;
|
||||||
|
this.originalText = this.item.node.text.na_web;
|
||||||
|
this.editorConfig.simpleUpload.headers.textId = this.item.node.text.id;
|
||||||
|
|
||||||
|
}
|
||||||
|
//this.getText();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getCookie: function (name){
|
||||||
|
var cookieValue = null;
|
||||||
|
if (document.cookie && document.cookie != '') {
|
||||||
|
var cookies = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < cookies.length; i++) {
|
||||||
|
var cookie = cookies[i].trim();
|
||||||
|
// Does this cookie string begin with the name we want?
|
||||||
|
|
||||||
|
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||||
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
},
|
||||||
|
getText: function() {
|
||||||
|
this.loading = true;
|
||||||
|
console.log(this.item);
|
||||||
|
console.log(this.item.node.text);
|
||||||
|
axios.get('/treenode/text/'+this.item.node.text)
|
||||||
|
.then((response) => {
|
||||||
|
this.text = response.data.na_web;
|
||||||
|
this.loading = false;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.loading = false;
|
||||||
|
console.log(err);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
saveText: function() {
|
||||||
|
console.log("Saving text");
|
||||||
|
console.log(this.currentText);
|
||||||
|
if (this.create){
|
||||||
|
console.log(this.refnode);
|
||||||
|
console.log(this.where);
|
||||||
|
axios.post('/api/textnode/',{
|
||||||
|
'text': { 'na_web': this.currentText},
|
||||||
|
'refnode': this.refnode.id,
|
||||||
|
'where': this.where
|
||||||
|
}).then(response => {
|
||||||
|
this.originalText = response.data.text.na_web;
|
||||||
|
this.loading = false;
|
||||||
|
this.$root.$emit('updateData',"textNode create update");
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
this.errors.push(e)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
axios.put('/api/textnode/'+this.item.node.id+'/',{
|
||||||
|
'text': { 'na_web': this.currentText},
|
||||||
|
'id': this.item.node.id
|
||||||
|
}).then(response => {
|
||||||
|
this.originalText = response.data.text.na_web;
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
this.errors.push(e)
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
this.editorShow = false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
.changed {
|
||||||
|
background-color: 'yellow';
|
||||||
|
}
|
||||||
|
</style>
|
161
vue_frontend/src/components/TreeNode.vue
Normal file
161
vue_frontend/src/components/TreeNode.vue
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div :class="editorMode ? 'treenode-org' : 'treenode'">
|
||||||
|
<!--b v-if="v_tematu">v tematu</b>
|
||||||
|
<b v-if="visible">visible</b>
|
||||||
|
Force visible: {{String(force_visible)}}-->
|
||||||
|
<component :is='item.node.polymorphic_ctype.model' :item='item' :key='item.node.id'
|
||||||
|
:editorMode="editorMode"
|
||||||
|
:debugMode="debugMode"></component>
|
||||||
|
|
||||||
|
|
||||||
|
<button v-if="debugMode" v-on:click="debugShow = !debugShow" class="nodebug">Ladící data</button> <!-- bude tu nějaký if na class="nodebug", v debug módu bude tlačítko vidět, jinak ne -->
|
||||||
|
<div v-if="debugShow">
|
||||||
|
<pre>{{ item.node.polymorphic_ctype.model }}</pre>
|
||||||
|
<pre>{{ item }}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="item.children.length === 0">
|
||||||
|
<div v-if="item.appendable_children.length > 0 && editorMode">
|
||||||
|
<b>Vložit jako syna: </b>
|
||||||
|
<addnewnode :types="item.appendable_children" :refnode="item.node" where="syn" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else :class="editorMode ? 'children-org' : 'children'"> <!-- bude tu nějaký if na class="children" -->
|
||||||
|
<div v-if="item.children.length > 0 && item.children[0].appendable_siblings.length > 0 && editorMode">
|
||||||
|
<b>Vložit před: </b>
|
||||||
|
<addnewnode :types="item.children[0].appendable_siblings" :refnode="item.children[0].node" where="pred" />
|
||||||
|
</div>
|
||||||
|
<div v-if="item.node.polymorphic_ctype.model==='temavcislenode'">
|
||||||
|
<!--Children: {{String(showChildren)}}-->
|
||||||
|
<div v-for="(chld, index) in item.children" v-bind:key="chld.nazev" >
|
||||||
|
<!--Hide: {{hideNode(chld)}}, v tematu: {{v_tematu}}, force_visible: {{force_visible}}-->
|
||||||
|
<div v-if="!hideNode(chld)">
|
||||||
|
<div v-if="chld.node.polymorphic_ctype.model==='ulohazadaninode'">
|
||||||
|
<button v-if="showChildren" v-on:click="showChildren=!showChildren"> Schovat </button>
|
||||||
|
<button v-else v-on:click="showChildren=!showChildren"> Rozbalit </button>
|
||||||
|
<TreeNode :item="chld" :v_tematu="true"
|
||||||
|
:force_visible="showChildren"
|
||||||
|
:editorMode="editorMode"
|
||||||
|
:debugMode="debugMode">
|
||||||
|
</TreeNode>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<TreeNode :item="chld" :v_tematu="true"
|
||||||
|
:force_visible="showChildren"
|
||||||
|
:editorMode="editorMode"
|
||||||
|
:debugMode="debugMode">
|
||||||
|
</TreeNode>
|
||||||
|
</div>
|
||||||
|
<div v-if="chld.appendable_siblings.length > 0 && editorMode" >
|
||||||
|
<b v-if="index < (item.children.length - 1)">Vložit mezi: </b>
|
||||||
|
<b v-else>Vložit za: </b>
|
||||||
|
<addnewnode :types="chld.appendable_siblings" :refnode="chld.node" where="za" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button v-if="showChildren" v-on:click="showChildren=!showChildren"> Schovat </button>
|
||||||
|
<button v-else v-on:click="showChildren=!showChildren"> Rozbalit </button>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div v-for="(chld, index) in item.children" v-bind:key="chld.nazev" >
|
||||||
|
<div v-if="v_tematu && chld.node.polymorphic_ctype.model==='ulohazadaninode'">
|
||||||
|
<div> Tady možná něco je </div>
|
||||||
|
<TreeNode :item="chld" :v_tematu="v_tematu"
|
||||||
|
:force_visible="force_visible"
|
||||||
|
:editorMode="editorMode"
|
||||||
|
:debugMode="debugMode">
|
||||||
|
</TreeNode>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<TreeNode :item="chld" :v_tematu="v_tematu"
|
||||||
|
:force_visible="force_visible"
|
||||||
|
:editorMode="editorMode"
|
||||||
|
:debugMode="debugMode">
|
||||||
|
</TreeNode>
|
||||||
|
</div>
|
||||||
|
<div v-if="chld.appendable_siblings.length > 0 && editorMode" >
|
||||||
|
<b v-if="index < (item.children.length - 1)">Vložit mezi: </b>
|
||||||
|
<b v-else>Vložit za: </b>
|
||||||
|
<addnewnode :types="chld.appendable_siblings" :refnode="chld.node" where="za" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import rocniknode from './RocnikNode.vue'
|
||||||
|
import cislonode from './CisloNode.vue'
|
||||||
|
import temavcislenode from './TemaVCisleNode.vue'
|
||||||
|
import castnode from './CastNode.vue'
|
||||||
|
import textnode from './TextNode.vue'
|
||||||
|
import ulohazadaninode from './UlohaZadaniNode.vue'
|
||||||
|
import ulohavzoraknode from './UlohaVzorakNode.vue'
|
||||||
|
import addnewnode from './AddNewNode.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TreeNode',
|
||||||
|
components: {
|
||||||
|
rocniknode,
|
||||||
|
cislonode,
|
||||||
|
temavcislenode,
|
||||||
|
castnode,
|
||||||
|
textnode,
|
||||||
|
ulohazadaninode,
|
||||||
|
ulohavzoraknode,
|
||||||
|
addnewnode
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
debugShow: false,
|
||||||
|
showChildren: false
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
item: Object,
|
||||||
|
force_visible: Boolean,
|
||||||
|
v_tematu: Boolean,
|
||||||
|
editorMode: Boolean,
|
||||||
|
debugMode: Boolean,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
hideNode: function(chld){
|
||||||
|
if (this.showChildren || this.force_visible){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (chld.node.polymorphic_ctype.model === 'ulohazadaninode'){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
|
||||||
|
.treenode-org {
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
border: #6a0043 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.children-org {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px;
|
||||||
|
border: #6a0043 2px dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodebug {
|
||||||
|
/* display: none; */
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
75
vue_frontend/src/components/TreeNodeRoot.vue
Normal file
75
vue_frontend/src/components/TreeNodeRoot.vue
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<div id="loading" v-if="loading">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
<!--pre>
|
||||||
|
{{item}}
|
||||||
|
</pre-->
|
||||||
|
<button v-show="editorMode" v-on:click="editorMode = false">Vypnout editační mód</button>
|
||||||
|
<button v-show="!editorMode" v-on:click="editorMode = true">Zapnout editační mód</button>
|
||||||
|
<button v-show="debugMode" v-on:click="debugMode = false">Vypnout ladicí mód</button>
|
||||||
|
<button v-show="!debugMode" v-on:click="debugMode = true">Zapnout ladicí mód</button>
|
||||||
|
<TreeNode :item="item" :editorMode="editorMode" :debugMode="debugMode"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TreeNode from './TreeNode.vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
TreeNode,
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
loading: true,
|
||||||
|
item: null,
|
||||||
|
tnid: 1,
|
||||||
|
editorMode: false,
|
||||||
|
debugMode: false,
|
||||||
|
}),
|
||||||
|
props:{
|
||||||
|
tnid: Number,
|
||||||
|
tnsource: String,
|
||||||
|
editorMode: Boolean,
|
||||||
|
debugMode: Boolean,
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
if (this.tnsource && this.tnsource=='inline'){
|
||||||
|
let data = JSON.parse(document.getElementById('vuedata').textContent);
|
||||||
|
this.tnid = data.treenode;
|
||||||
|
}
|
||||||
|
this.getArticles();
|
||||||
|
this.$root.$on('updateData',(arg) => {
|
||||||
|
console.log(arg);
|
||||||
|
this.getArticles();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getArticles: function() {
|
||||||
|
this.loading = true;
|
||||||
|
axios.get('/treenode/'+this.tnid+'/json/')
|
||||||
|
.then((response) => {
|
||||||
|
this.item = response.data;
|
||||||
|
this.loading = false;
|
||||||
|
console.log('Data updated');
|
||||||
|
this.$root.$emit('dataUpdated',"dataUpdated");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.loading = false;
|
||||||
|
console.log(err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
updateData: function(){
|
||||||
|
this.getArticles()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '../../../mamweb/static/css/mamweb.css';
|
||||||
|
</style>
|
75
vue_frontend/src/components/UlohaVzorakNode.vue
Normal file
75
vue_frontend/src/components/UlohaVzorakNode.vue
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<template>
|
||||||
|
<div class="ulohavzoraknode">
|
||||||
|
<!--pre>UlohaVzorakNode {{item}} {{typeof(item)}}</pre-->
|
||||||
|
<h5>Řešení {{item.node.uloha.cislo_zadani.poradi}}.{{ item.node.uloha.kod }}: {{ item.node.uloha.nazev }}</h5>
|
||||||
|
<button v-if="editorMode" v-on:click="showSelect=!showSelect" class="upravit">Upravit</button>
|
||||||
|
<div v-if="showSelect">
|
||||||
|
<form class="searchForm" v-on:submit.prevent="submitSearch">
|
||||||
|
<input type="text" v-model="searchQuery" placeholder="Napište název" @keyup="submitSearch">
|
||||||
|
</form>
|
||||||
|
<div class="searchResult" v-show="isResult">
|
||||||
|
<ul>
|
||||||
|
<li v-for="res in searchResults" :key="res.id" v-on:click="setSelected(res)">{{res.nazev}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UlohaVzorakNode',
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
isResult: false,
|
||||||
|
searchQuery: '',
|
||||||
|
searchResults: [],
|
||||||
|
showSelect: false,
|
||||||
|
selected: null,
|
||||||
|
selected_id: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
item: Object,
|
||||||
|
create: Boolean,
|
||||||
|
showSelect: Boolean,
|
||||||
|
editorMode: Boolean,
|
||||||
|
},
|
||||||
|
mounted: function(){
|
||||||
|
if (this.item.node.uloha === null){
|
||||||
|
console.log("Uloha je null!");
|
||||||
|
console.log(this.item);
|
||||||
|
}
|
||||||
|
if (this.create){
|
||||||
|
this.showSelect = true;
|
||||||
|
console.log('Creating');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submitSearch: function(){
|
||||||
|
if (this.searchQuery.length < 3) { return;}
|
||||||
|
var reqURL = "/api/ulohavzoraknode/?nazev="+this.searchQuery;
|
||||||
|
axios.get(reqURL).then( (response) => {
|
||||||
|
this.searchResults = response.data.results;
|
||||||
|
this.isResult = true;
|
||||||
|
console.log("Got:");
|
||||||
|
console.log(this.searchResults);
|
||||||
|
}).catch( (err) => { /* fail response msg */
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setSelected: function(res){
|
||||||
|
this.searchQuery = res.nazev
|
||||||
|
this.selected_id = res.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.upravit {
|
||||||
|
margin-top:-40px;
|
||||||
|
}
|
||||||
|
</style>
|
23
vue_frontend/src/components/UlohaZadaniNode.vue
Normal file
23
vue_frontend/src/components/UlohaZadaniNode.vue
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<template>
|
||||||
|
<div class="ulohazadaninode">
|
||||||
|
<!--pre>UlohaZadaniNode {{item.node.uloha}} {{typeof(item)}}</pre-->
|
||||||
|
<h5>Zadání {{item.node.uloha.cislo_zadani.poradi}}.{{ item.node.uloha.kod }}: {{ item.node.uloha.nazev }}</h5>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'UlohaZadaniNode',
|
||||||
|
props: {
|
||||||
|
item: Object,
|
||||||
|
created: Boolean
|
||||||
|
,
|
||||||
|
mounted: function(){
|
||||||
|
if (this.item.node.uloha === null){
|
||||||
|
console.log("Uloha je null!");
|
||||||
|
console.log(this.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
12
vue_frontend/src/main.js
Normal file
12
vue_frontend/src/main.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
import CKEditor from '@ckeditor/ckeditor5-vue'
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
Vue.use(CKEditor);
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
render: h => h(App),
|
||||||
|
}).$mount('#app')
|
33
vue_frontend/src/router/index.js
Normal file
33
vue_frontend/src/router/index.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
import Router from 'vue-router'
|
||||||
|
import TreeNodeRoot from '../components/TreeNodeRoot.vue'
|
||||||
|
|
||||||
|
Vue.use(Router)
|
||||||
|
|
||||||
|
export default new Router({
|
||||||
|
mode: 'history',
|
||||||
|
linkActiveClass: 'active',
|
||||||
|
routes: [{
|
||||||
|
path: '/temp/vue',
|
||||||
|
name: 'treenodedefault',
|
||||||
|
props: {'tnid': 23},
|
||||||
|
component: TreeNodeRoot
|
||||||
|
}, {
|
||||||
|
path: '/temp/vue/:tnid',
|
||||||
|
name: 'treenode',
|
||||||
|
props: true,
|
||||||
|
component: TreeNodeRoot
|
||||||
|
}, {
|
||||||
|
path: '/zadani/aktualni',
|
||||||
|
name: 'treenode_zadani',
|
||||||
|
props: {'tnid': 23},
|
||||||
|
component: TreeNodeRoot
|
||||||
|
}, {
|
||||||
|
path: '/cislo/:cislo',
|
||||||
|
name: 'treenode_cislo',
|
||||||
|
props: {'tnsource':'inline'},
|
||||||
|
component: TreeNodeRoot
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
61
vue_frontend/vue.config.js
Normal file
61
vue_frontend/vue.config.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
const BundleTracker = require("webpack-bundle-tracker");
|
||||||
|
|
||||||
|
const pages = {
|
||||||
|
'vue_app_01': {
|
||||||
|
entry: './src/main.js',
|
||||||
|
chunks: ['chunk-vendors']
|
||||||
|
},
|
||||||
|
/* 'vue_app_02': {
|
||||||
|
entry: './src/newhampshir.js',
|
||||||
|
chunks: ['chunk-vendors']
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
pages: pages,
|
||||||
|
filenameHashing: false,
|
||||||
|
productionSourceMap: false,
|
||||||
|
publicPath: process.env.NODE_ENV === 'production'
|
||||||
|
? '/static/seminar/vue/'
|
||||||
|
: 'http://localhost:8080/',
|
||||||
|
outputDir: '../seminar/static/seminar/vue/',
|
||||||
|
|
||||||
|
chainWebpack: config => {
|
||||||
|
|
||||||
|
config.optimization
|
||||||
|
.splitChunks({
|
||||||
|
cacheGroups: {
|
||||||
|
vendor: {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: "chunk-vendors",
|
||||||
|
chunks: "all",
|
||||||
|
priority: 1
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(pages).forEach(page => {
|
||||||
|
config.plugins.delete(`html-${page}`);
|
||||||
|
config.plugins.delete(`preload-${page}`);
|
||||||
|
config.plugins.delete(`prefetch-${page}`);
|
||||||
|
})
|
||||||
|
|
||||||
|
config
|
||||||
|
.plugin('BundleTracker')
|
||||||
|
.use(BundleTracker, [{filename: '../vue_frontend/webpack-stats.json'}]);
|
||||||
|
|
||||||
|
config.resolve.alias
|
||||||
|
.set('__STATIC__', 'static')
|
||||||
|
|
||||||
|
config.devServer
|
||||||
|
.public('http://localhost:8080')
|
||||||
|
.host('localhost')
|
||||||
|
.port(8080)
|
||||||
|
.hotOnly(true)
|
||||||
|
.watchOptions({poll: 1000})
|
||||||
|
.https(false)
|
||||||
|
.headers({"Access-Control-Allow-Origin": ["*"]})
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
8544
vue_frontend/yarn.lock
Normal file
8544
vue_frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue