Merge branch 'data_migrations' into test
This commit is contained in:
commit
99d7bd50a1
54 changed files with 91581 additions and 988 deletions
2
Makefile
2
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}
|
||||||
|
|
File diff suppressed because one or more lines are too long
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,9 @@ INSTALLED_APPS = (
|
||||||
'imagekit',
|
'imagekit',
|
||||||
|
|
||||||
'polymorphic',
|
'polymorphic',
|
||||||
|
|
||||||
|
'webpack_loader',
|
||||||
|
'rest_framework',
|
||||||
|
|
||||||
# MaMweb
|
# MaMweb
|
||||||
'mamweb',
|
'mamweb',
|
||||||
|
@ -184,6 +187,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
|
||||||
|
|
||||||
|
|
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;
|
||||||
|
}
|
|
@ -101,6 +101,26 @@ h6 {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin: 10px 0px 10px 0px;
|
||||||
|
padding: 4px 0; /*vertikální centování textu*/
|
||||||
|
text-align: center;
|
||||||
|
background-color: #e84e10;
|
||||||
|
color: #fffbf6;
|
||||||
|
font-size: 150%;
|
||||||
|
font-weight: bold;
|
||||||
|
font-variant: small-caps;
|
||||||
|
filter: drop-shadow(0px 5px 5px rgba(0, 0, 0, 0.4));
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
left:2px;
|
||||||
|
background-color: #df490e;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.org-logged-in .mam-text-plugin {
|
.org-logged-in .mam-text-plugin {
|
||||||
border: dashed 1px #6a0043;
|
border: dashed 1px #6a0043;
|
||||||
|
@ -286,7 +306,11 @@ ul.submenu li>a:hover {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.menu li.active>a, ul.submenu li.active>a {
|
ul.menu li.active>a {
|
||||||
|
color: #f9d59e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.submenu li.active>a {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,13 +391,82 @@ input[type="file"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.field-with-comment:hover span.field-comment{
|
.field-with-comment:hover span.field-comment{
|
||||||
display:block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* titulni stranka */
|
||||||
|
|
||||||
|
.titulnistrana {
|
||||||
|
display: flex;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titulnistrana h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zjistit_vic{
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zjistit_vic hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graf-svg {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#svg-graf {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titulnistrana_obsah {
|
||||||
|
width: 66%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vitej_titulka, .temata_titulka {
|
||||||
|
width: 49%;
|
||||||
|
padding: 10px;
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titulnistrana_novinky {
|
||||||
|
width: 33%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.novinka_obrazek {
|
||||||
|
margin: 10px 0px 10px 0px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.novinka_datum {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.novinka_autor {
|
||||||
|
text-align: right;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.org-text {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.odpocet {
|
||||||
|
margin: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* Zmenšování displeje
|
* Zmenšování displeje
|
||||||
***********************/
|
***********************/
|
||||||
|
@ -403,42 +496,22 @@ input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.novinky{
|
ul.menu {
|
||||||
max-width: 100%;
|
font-size: 90%;
|
||||||
margin-left: auto;
|
margin-top: -7px;
|
||||||
margin-right: auto;
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.graf{
|
|
||||||
width: 70%;
|
|
||||||
float: none;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
#svg-graf{
|
|
||||||
width: 100%;
|
|
||||||
height: auto;;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.menu {
|
ul.menu li {
|
||||||
font-size: 90%;
|
margin-top: 10px; /* posunutí textu hlavního menu níže */
|
||||||
margin-top: -7px;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ul.menu li {
|
ul.submenu li {
|
||||||
margin-top: 10px; /* posunutí textu hlavního menu níže */
|
margin-top: 0px; /* aby se spolu s textem hlavního menu neposunoval níže i text submenu */
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.submenu li {
|
|
||||||
margin-top: 0px; /* aby se spolu s textem hlavního menu neposunoval níže i text submenu */
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.submenu {
|
|
||||||
margin-top: 8px; /* mezera mezi hlavním menu a submenu */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ul.submenu {
|
||||||
|
margin-top: 8px; /* mezera mezi hlavním menu a submenu */
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,11 +543,53 @@ ul.submenu {
|
||||||
display: inline-grid;
|
display: inline-grid;
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* titulni stranka */
|
||||||
|
|
||||||
|
.titulnistrana {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graf {
|
||||||
|
padding-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titulnistrana_obsah {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vitej_titulka, .temata_titulka {
|
||||||
|
width: 49%;
|
||||||
|
padding: 10px;
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titulnistrana_novinky {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
padding: 10px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#svg-graf {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
padding: 10px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.zjistit_vic hr {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* malý tablet, mobil */
|
/* malý tablet, mobil */
|
||||||
@media (max-width: 650px) {
|
@media (max-width: 650px) {
|
||||||
|
|
||||||
|
.no-mobile{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
#hide-if-small.login-bar-flatpage {
|
#hide-if-small.login-bar-flatpage {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -611,19 +726,35 @@ ul.submenu {
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.novinky {
|
|
||||||
max-width: 100%;
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.graf {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.form td, table.form tr {
|
table.form td, table.form tr {
|
||||||
display: inherit;
|
display: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* titulni stranka */
|
||||||
|
|
||||||
|
.titulnistrana {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graf {
|
||||||
|
padding-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titulnistrana_obsah {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vitej_titulka, .temata_titulka {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titulnistrana_novinky {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*stránka organizátorů*/
|
/*stránka organizátorů*/
|
||||||
|
@ -704,11 +835,6 @@ div.org_email {
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Style the front side (fallback if image is missing) */
|
|
||||||
.flip-card-front {
|
|
||||||
background-color: #bbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.flip-card-foto img {
|
div.flip-card-foto img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -724,6 +850,10 @@ div.flip-card-foto img {
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#archiv.flip-card-back {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* karty archiv */
|
/* karty archiv */
|
||||||
|
|
||||||
div.popis_rocniku {
|
div.popis_rocniku {
|
||||||
|
@ -920,46 +1050,8 @@ div.cislo_odkazy ul {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* titulni stranka */
|
/**/
|
||||||
|
|
||||||
.zjistit_vic{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.graf{
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.novinky{
|
|
||||||
float: right;
|
|
||||||
max-width: 42%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.novinka_obrazek img {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.novinka_obrazek {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px; /*FIXME*/
|
|
||||||
}
|
|
||||||
|
|
||||||
div.org-text {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.nahledy_cisel {
|
|
||||||
float: right;
|
|
||||||
height: 297px;
|
|
||||||
width: 420px;
|
|
||||||
position: relative;
|
|
||||||
margin-right: 10%;
|
|
||||||
margin-bottom: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.nahledy_cisel div, div.nahledy_cisel img {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
ul.form {
|
ul.form {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
|
@ -984,3 +1076,20 @@ p.gdpr {
|
||||||
div.gdpr {
|
div.gdpr {
|
||||||
font-size: 6pt;
|
font-size: 6pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Jak řešit */
|
||||||
|
|
||||||
|
.jakresit img {
|
||||||
|
width: 33%;
|
||||||
|
padding: 10px;
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-width: 860px) {
|
||||||
|
.jakresit img {
|
||||||
|
margin: auto;
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 360px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
26847
mamweb/static/images/jakresit_1.svg
Normal file
26847
mamweb/static/images/jakresit_1.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 1.8 MiB |
26847
mamweb/static/images/jakresit_2.svg
Normal file
26847
mamweb/static/images/jakresit_2.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 1.8 MiB |
26847
mamweb/static/images/jakresit_3.svg
Normal file
26847
mamweb/static/images/jakresit_3.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 1.8 MiB |
|
@ -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">
|
||||||
|
@ -56,14 +57,17 @@
|
||||||
<div class='col-md-12'>
|
<div class='col-md-12'>
|
||||||
<a href='/'>
|
<a href='/'>
|
||||||
<div id="title" >M&M - korespondenční seminář a časopis MFF UK</div>
|
<div id="title" >M&M - korespondenční seminář a časopis MFF UK</div>
|
||||||
<div id="header" style="background-image: url('{{ fotka }}')">
|
<div id="header">
|
||||||
|
<div class="no-mobile" style="background-image: url('{{ fotka }}')">
|
||||||
{# TODO style=… není fancy řešení, ale u <img> se bojím, že mi to rozbije vzhled #}
|
{# TODO style=… není fancy řešení, ale u <img> se bojím, že mi to rozbije vzhled #}
|
||||||
{% sitetree_menu from "main_menu" include "trunk" template "logo.html" %}
|
{% sitetree_menu from "main_menu" include "trunk" template "logo.html" %}
|
||||||
|
</div>
|
||||||
<img class="logo-mobile" src="{% static 'images/logo-mobile.svg' %}" />
|
<img class="logo-mobile" src="{% static 'images/logo-mobile.svg' %}" />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
<div class='col-md-12'>
|
<div class='col-md-12'>
|
||||||
|
|
||||||
|
@ -73,6 +77,9 @@
|
||||||
|
|
||||||
{# ========= MENU MOBILE ========== #}
|
{# ========= MENU MOBILE ========== #}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!--Navbar-->
|
<!--Navbar-->
|
||||||
<nav class="nav-button">
|
<nav class="nav-button">
|
||||||
|
|
||||||
|
@ -95,13 +102,15 @@
|
||||||
|
|
||||||
{# ========= END MENU ========== #}
|
{# ========= END MENU ========== #}
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
<div class='row content'>
|
<div class='row content'>
|
||||||
<div class='col-md-12'>
|
<div class='col-md-12'>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
<div class='col-md-12'>
|
<div class='col-md-12'>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
|
@ -110,6 +119,7 @@
|
||||||
<p class="license-mobile">Korespondenční seminář M&M organizují převážně studenti <a href="https://www.mff.cuni.cz/">MFF UK</a>. Organizaci semináře a vydávání časopisu podporuje <a href="https://jcmf.cz/">Jednota českých matematiků a fyziků</a>. S obsahem webu M&M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p>
|
<p class="license-mobile">Korespondenční seminář M&M organizují převážně studenti <a href="https://www.mff.cuni.cz/">MFF UK</a>. Organizaci semináře a vydávání časopisu podporuje <a href="https://jcmf.cz/">Jednota českých matematiků a fyziků</a>. S obsahem webu M&M je možné nakládat dle licence <a href="https://creativecommons.org/licenses/by/3.0/cz/">Creative Commons Attribution 3.0</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="{% static 'js/bootstrap.js' %}"></script>
|
<script src="{% static 'js/bootstrap.js' %}"></script>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -706,6 +705,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
|
||||||
(STAV_SMAZANY, 'Smazaný'),
|
(STAV_SMAZANY, 'Smazaný'),
|
||||||
]
|
]
|
||||||
stav = models.CharField('stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH)
|
stav = models.CharField('stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH)
|
||||||
|
# Téma je taky Problém, takže má stavy, "zadané" témátko je aktuálně otevřené a dá se k němu něco poslat (řešení nebo článek)
|
||||||
|
|
||||||
zamereni = TaggableManager(verbose_name='zaměření',
|
zamereni = TaggableManager(verbose_name='zaměření',
|
||||||
help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True)
|
help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True)
|
||||||
|
@ -745,6 +745,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
|
||||||
def verejne(self):
|
def verejne(self):
|
||||||
# FIXME: Tohle se liší podle typu problému, má se udělat polymorfně.
|
# FIXME: Tohle se liší podle typu problému, má se udělat polymorfně.
|
||||||
# Zatím je tu jen dummy fail-safe default: nic není veřejné.
|
# Zatím je tu jen dummy fail-safe default: nic není veřejné.
|
||||||
|
# Doporučené řešení: dělat tohle podle stavu problému a veřejnosti čísla, ve kterém je
|
||||||
return False
|
return False
|
||||||
# FIXME: Tohle je blbost
|
# FIXME: Tohle je blbost
|
||||||
return (self.cislo_zadani and self.cislo_zadani.verejne())
|
return (self.cislo_zadani and self.cislo_zadani.verejne())
|
||||||
|
@ -843,9 +844,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:
|
||||||
|
@ -1361,6 +1360,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):
|
||||||
|
|
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';
|
||||||
|
|
||||||
|
}
|
|
@ -8,10 +8,6 @@
|
||||||
{% endblock %}{% endblock %}
|
{% endblock %}{% endblock %}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<!-- <div class='nahledy_cisel'>
|
|
||||||
{% autoescape off %}{{ nahledy }}{% endautoescape %}
|
|
||||||
</div>-->
|
|
||||||
|
|
||||||
{% for rocnik, url_png in object_list.items %}
|
{% for rocnik, url_png in object_list.items %}
|
||||||
|
|
||||||
<div class="rocnik_pole">
|
<div class="rocnik_pole">
|
||||||
|
@ -33,7 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flip-card-back">
|
<div class="flip-card-back" id="archiv">
|
||||||
<div class="popis_rocniku">
|
<div class="popis_rocniku">
|
||||||
Jednotlivá čísla:
|
Jednotlivá čísla:
|
||||||
<ul>
|
<ul>
|
||||||
|
|
16
seminar/templates/seminar/jak-resit.html
Normal file
16
seminar/templates/seminar/jak-resit.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% load humanize %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class=jakresit>
|
||||||
|
|
||||||
|
<img class="jakresit_obrazek" alt="" src="{% static 'images/jakresit_1.svg' %}" />
|
||||||
|
<img class="jakresit_obrazek" alt="" src="{% static 'images/jakresit_2.svg' %}" />
|
||||||
|
<img class="jakresit_obrazek" alt="" src="{% static 'images/jakresit_3.svg' %}" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -9,7 +9,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if novinka.zverejneno or user.je_org %}
|
{% if novinka.zverejneno or user.je_org %}
|
||||||
{# datum #}
|
{# datum #}
|
||||||
<div><b>{{novinka.datum}}</b></div>
|
<div class=novinka_datum>{{novinka.datum}}</div>
|
||||||
{# text #}
|
{# text #}
|
||||||
{{ novinka.text | safe }}
|
{{ novinka.text | safe }}
|
||||||
{# obrazek #}
|
{# obrazek #}
|
||||||
|
@ -25,12 +25,12 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{# autor #}
|
{# autor #}
|
||||||
<div class=novinky_name><p>{{novinka.autor.first_name}}
|
<div class=novinka_autor>
|
||||||
{% if novinka.autor.organizator.prezdivka%}
|
{{novinka.autor.osoba.jmeno}}
|
||||||
„{{novinka.autor.organizator.prezdivka}}“
|
{% if novinka.autor.osoba.prezdivka%}
|
||||||
|
„{{novinka.autor.osoba.prezdivka}}“
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{novinka.autor.last_name}}
|
{{novinka.autor.osoba.prijmeni}}
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not novinka.zverejneno and user.je_org %}
|
{% if not novinka.zverejneno and user.je_org %}
|
||||||
|
|
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,25 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<p style="text-align:justify">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 style="text-align:justify"><a href="/co-je-MaM/jak-resit/">Jak řešit téma?</a></p>
|
||||||
|
|
||||||
|
<p style="text-align:justify"> </p>
|
||||||
|
|
||||||
|
<h1>Aktuální témata</h1>
|
||||||
|
|
||||||
{% for tematko in tematka %}
|
{% for tematko in tematka %}
|
||||||
<h1>{{tematko.nazev}}</h1>
|
<h2>{{tematko.nazev}}</h2>
|
||||||
|
<div class="tematko-obrazek">
|
||||||
|
{% if tematko.obrazek %}
|
||||||
|
<a href="{{tematko.obrazek.url}}" class="ref-tema-obr"><img src="{{tematko.obrazek.url}}" height="{{tematko.obrazek.height}}" alt="{{tematko.nazev}}"></a>
|
||||||
|
{% else %} {# pokud témátko nemá fotku, zobrazuje se defaultní obrázek #}
|
||||||
|
{% load static %} <img src="{% static 'images/no-photo.png' %}" height=200px alt="{{tematko.nazev}}">
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>{{tematko.abstrakt}}</p>
|
<p>{{tematko.abstrakt}}</p>
|
||||||
<ul>
|
|
||||||
{% for cislo in tematko.cisla %}
|
|
||||||
<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{cislo.0.1}}">{{cislo.0.0}}</a></li>
|
|
||||||
<ul>
|
|
||||||
{% for odkaz in cislo.1 %}
|
|
||||||
<li><a href="/{{rocnik}}/t{{tematko.kod}}/#{{odkaz.1}}">{{odkaz.0}}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -5,32 +5,53 @@
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{# Uvitaci text #}
|
|
||||||
<h1>
|
|
||||||
{% block nadpis1a %}{% block nadpis1b %}
|
|
||||||
Vítej!
|
|
||||||
{% endblock %}{% endblock %}
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
M&M je korespondenční seminář. Několikrát do roka zdarma vydáváme časopis a v něm zajímavé podněty k přemýšlení. Ty na ně můžeš reagovat.<br>
|
|
||||||
|
|
||||||
M&M je taky soutěž. Můžeš vyhrát knížky, deskovky nebo dokonce dort. Můžeš se dostat na matfyz bez přijímaček. A především s námi můžeš jet na skvělé soustředění.
|
{% if nejblizsi_deadline %}
|
||||||
</p>
|
<div class="odpocet">
|
||||||
|
<p><b><big>Do konce <a href="/zadani/aktualni/">odeslání řešení</a> {% if typ_deadline == 'soustredeni' %}(pro účast na soustředění) {% elif typ_deadline == 'preddeadline' %}(pro otištění došlých řešení) {% endif %}zbývá:
|
||||||
<div class="novinky">
|
{{nejblizsi_deadline|timeuntil}}</big></b></p>
|
||||||
{% if dead %}
|
|
||||||
<div class="odpocet">
|
|
||||||
<p><b>Do konce <a href="/zadani/aktualni/">odeslání řešení</a> {% if deadline_soustredeni %}(pro účast na soustředění) {% endif %}zbývá:<br>
|
|
||||||
<big>{{ted|timesince:dead}}</big></b></p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{# Novinky #}
|
|
||||||
<h1>Novinky</h1>
|
|
||||||
{% include 'seminar/novinky.html' %}
|
|
||||||
|
|
||||||
<a href='/stare-novinky/'>Archiv novinek</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class=titulnistrana>
|
||||||
|
|
||||||
|
<div class="titulnistrana_obsah">
|
||||||
|
|
||||||
|
<div class="vitej_titulka">
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
{% block nadpis1a %}
|
||||||
|
Vítej
|
||||||
|
{% endblock %}
|
||||||
|
mezi námi
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
M&M je korespondenční seminář. Vydáváme časopis a v něm zajímavé podněty k přemýšlení. Ty na ně můžeš reagovat,
|
||||||
|
experimentovat a objevovat s námi fascinující zákoutí matiky, fyziky a informatiky.
|
||||||
|
<a href="auth/registrace"> <div class="button"> Zaregistruj se! </div> </a> {# FIXME odkaz #}
|
||||||
|
M&M je taky soutěž. Za svá řešení dostaneš body a můžeš vyhrát zajímavé ceny, dostat se
|
||||||
|
na Matfyz bez přijímaček a především, můžeš s námi jet na skvělé soustředění.
|
||||||
|
<a href="cojemam/odmeny"> <div class="button"> Co můžeš vyhrát? </div> </a> {# FIXME odkaz #}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="temata_titulka">
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Řeš témata!
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Přidej se k nám! Pusť se do řešení témát.
|
||||||
|
{% for tema in aktualni_temata %}
|
||||||
|
<a href="{{ tema.url }}"> <div class="button"> {{ tema.nazev }} </div> </a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="graf">
|
<div class="graf">
|
||||||
|
|
||||||
<div class="graf-svg">
|
<div class="graf-svg">
|
||||||
|
@ -38,8 +59,24 @@ M&M je korespondenční seminář. Několikrát do roka zdarma vydáváme č
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="zjistit_vic">
|
<span class="zjistit_vic">
|
||||||
<h2><a href="/co-je-MaM/uvod/">Zjistit víc!</a></h2>
|
<h2><a href="/co-je-MaM/uvod/">Zjisti víc!</a></h2>
|
||||||
|
<hr>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="titulnistrana_novinky">
|
||||||
|
|
||||||
|
{# Novinky #}
|
||||||
|
<h1>Co je nového?</h1>
|
||||||
|
{% include 'seminar/novinky.html' %}
|
||||||
|
|
||||||
|
<a href='/stare-novinky/'>Archiv novinek</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% 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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -17,9 +17,17 @@ urlpatterns = [
|
||||||
path('archiv/temata/', views.ArchivTemataView.as_view()),
|
path('archiv/temata/', views.ArchivTemataView.as_view()),
|
||||||
|
|
||||||
path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'),
|
path('rocnik/<int:rocnik>/', views.RocnikView.as_view(), name='seminar_rocnik'),
|
||||||
path('cislo/<int:rocnik>.<int:cislo>/', views.CisloView.as_view(), name='seminar_cislo'), # odkomentované jenom kvůli testování archivu
|
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,7 +157,11 @@ 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'),
|
||||||
|
|
||||||
# Ceka na autocomplete v3
|
# Ceka na autocomplete v3
|
||||||
# path('autocomplete/organizatori/',
|
# path('autocomplete/organizatori/',
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from .views_all import *
|
from .views_all import *
|
||||||
from .autocomplete import *
|
from .autocomplete import *
|
||||||
|
from .views_rest import *
|
||||||
|
|
|
@ -16,15 +16,20 @@ 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.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
|
from datetime import timedelta, date, datetime, MAXYEAR
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
@ -44,14 +49,15 @@ import time
|
||||||
|
|
||||||
from seminar.utils import aktivniResitele, resi_v_rocniku
|
from seminar.utils import aktivniResitele, resi_v_rocniku
|
||||||
|
|
||||||
|
# ze starého modelu
|
||||||
def verejna_temata(rocnik):
|
#def verejna_temata(rocnik):
|
||||||
"""Vrací queryset zveřejněných témat v daném ročníku.
|
# """
|
||||||
"""
|
# Vrací queryset zveřejněných témat v daném ročníku.
|
||||||
return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod')
|
# """
|
||||||
|
# return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod')
|
||||||
def temata_v_rocniku(rocnik):
|
#
|
||||||
return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik)
|
#def temata_v_rocniku(rocnik):
|
||||||
|
# return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik)
|
||||||
|
|
||||||
def get_problemy_k_tematu(tema):
|
def get_problemy_k_tematu(tema):
|
||||||
return Problem.objects.filter(nadproblem = tema)
|
return Problem.objects.filter(nadproblem = tema)
|
||||||
|
@ -88,17 +94,99 @@ 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 = []
|
||||||
|
|
||||||
|
|
||||||
def treenode_strom_na_seznamy(node):
|
|
||||||
out = TNLData(node)
|
@classmethod
|
||||||
for ch in treelib.all_children(node):
|
def from_treenode(cls,anode,parent=None,index=None):
|
||||||
outitem = treenode_strom_na_seznamy(ch)
|
out = cls(anode,parent,index)
|
||||||
out.children.append(outitem)
|
for (idx,ch) in enumerate(treelib.all_children(anode)):
|
||||||
return out
|
outitem = cls.from_treenode(ch,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 __repr__(self):
|
||||||
|
return("TNL({})".format(self.node))
|
||||||
|
|
||||||
class TreeNodeView(generic.DetailView):
|
class TreeNodeView(generic.DetailView):
|
||||||
model = s.TreeNode
|
model = s.TreeNode
|
||||||
|
@ -106,22 +194,180 @@ 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)
|
||||||
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).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()
|
# Teď potřebujeme doplnit tnldata do kontextu.
|
||||||
context['verejne'] = verejne
|
# 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)
|
||||||
|
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)
|
||||||
|
tnl_vzorak = TNLData.from_treenode(self.object.ulohavzoraknode)
|
||||||
|
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()
|
||||||
|
@ -137,7 +383,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:
|
||||||
|
@ -242,45 +500,51 @@ def spravne_novinky(request):
|
||||||
qs = qs.filter(zverejneno=True)
|
qs = qs.filter(zverejneno=True)
|
||||||
return qs.order_by('-datum')
|
return qs.order_by('-datum')
|
||||||
|
|
||||||
|
def aktualni_temata(rocnik):
|
||||||
|
"""
|
||||||
|
Vrací PolymorphicQuerySet témat v daném ročníku, ke kterým se aktuálně dá něco odevzdat.
|
||||||
|
"""
|
||||||
|
return Tema.objects.filter(rocnik=rocnik, stav='zadany').order_by('kod')
|
||||||
|
|
||||||
|
|
||||||
class TitulniStranaView(generic.ListView):
|
class TitulniStranaView(generic.ListView):
|
||||||
template_name='seminar/titulnistrana.html'
|
template_name='seminar/titulnistrana.html'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return spravne_novinky(self.request)[:5]
|
return spravne_novinky(self.request)[:3]
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(TitulniStranaView, self).get_context_data(**kwargs)
|
context = super(TitulniStranaView, self).get_context_data(**kwargs)
|
||||||
nastaveni = get_object_or_404(Nastaveni)
|
nastaveni = get_object_or_404(Nastaveni)
|
||||||
|
|
||||||
|
deadline_soustredeni = (nastaveni.aktualni_cislo.datum_deadline_soustredeni, "soustredeni")
|
||||||
|
preddeadline = (nastaveni.aktualni_cislo.datum_preddeadline, "preddeadline")
|
||||||
|
deadline = (nastaveni.aktualni_cislo.datum_deadline, "deadline")
|
||||||
|
|
||||||
# zjisteni spravneho terminu
|
try:
|
||||||
if nastaveni.aktualni_cislo.datum_deadline_soustredeni:
|
nejblizsi_deadline = sorted(filter(lambda dl: dl[0] is not None and dl[0] >= date.today(), [deadline_soustredeni, preddeadline, deadline]))[0]
|
||||||
cas_deadline_soustredeni = nastaveni.aktualni_cislo.\
|
except IndexError:
|
||||||
datum_deadline_soustredeni
|
nejblizsi_deadline = (None, None) # neni zadna aktualni deadline
|
||||||
if (datetime.now().date() <= cas_deadline_soustredeni):
|
|
||||||
cas_deadline = cas_deadline_soustredeni
|
|
||||||
deadline_soustredeni = True
|
|
||||||
else:
|
|
||||||
cas_deadline = nastaveni.aktualni_cislo.datum_deadline
|
|
||||||
deadline_soustredeni = False
|
|
||||||
else:
|
|
||||||
cas_deadline = nastaveni.aktualni_cislo.datum_deadline
|
|
||||||
deadline_soustredeni = False
|
|
||||||
|
|
||||||
# Pokud neni zverejnene cislo nezverejnuj odpocet
|
if nejblizsi_deadline[0] is not None:
|
||||||
if nastaveni.aktualni_cislo.verejne():
|
context['nejblizsi_deadline'] = datetime.combine(nejblizsi_deadline[0], datetime.max.time())
|
||||||
# pokus se zjistit termin odeslani a pokud neni zadany,
|
|
||||||
# nezverejnuj odpocet
|
|
||||||
context['deadline_soustredeni'] = deadline_soustredeni
|
|
||||||
try:
|
|
||||||
context['dead'] = datetime.combine(cas_deadline,
|
|
||||||
datetime.max.time())
|
|
||||||
context['ted'] = datetime.now()
|
|
||||||
except:
|
|
||||||
context['dead'] = None
|
|
||||||
else:
|
else:
|
||||||
context['dead'] = None
|
context['nejblizsi_deadline'] = None
|
||||||
context['deadline_soustredeni'] = deadline_soustredeni
|
|
||||||
|
context['typ_deadline'] = nejblizsi_deadline[1]
|
||||||
|
|
||||||
|
# Aktuální témata
|
||||||
|
nazvy_a_odkazy_na_aktualni_temata = []
|
||||||
|
akt_temata = aktualni_temata(nastaveni.aktualni_rocnik)
|
||||||
|
|
||||||
|
for tema in akt_temata:
|
||||||
|
# FIXME: netuším, jestli funguje tema.verejne_url(), nemáme testdata na témátka - je to asi url vzhledem k ročníku
|
||||||
|
nazvy_a_odkazy_na_aktualni_temata.append({'nazev':tema.nazev,'url':tema.verejne_url()})
|
||||||
|
|
||||||
|
context['aktualni_temata'] = nazvy_a_odkazy_na_aktualni_temata
|
||||||
|
|
||||||
|
print(context)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
class StareNovinkyView(generic.ListView):
|
class StareNovinkyView(generic.ListView):
|
||||||
|
@ -343,7 +607,8 @@ class ArchivView(generic.ListView):
|
||||||
### Výsledky
|
### Výsledky
|
||||||
|
|
||||||
def sloupec_s_poradim(setrizene_body):
|
def sloupec_s_poradim(setrizene_body):
|
||||||
""" Ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník
|
"""
|
||||||
|
Ze seznamu obsahujícího sestupně setřízené body řešitelů za daný ročník
|
||||||
vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.),
|
vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.),
|
||||||
podle toho, jak jdou za sebou ve výsledkovce.
|
podle toho, jak jdou za sebou ve výsledkovce.
|
||||||
Parametr:
|
Parametr:
|
||||||
|
@ -383,7 +648,8 @@ def sloupec_s_poradim(setrizene_body):
|
||||||
return sloupec_s_poradim
|
return sloupec_s_poradim
|
||||||
|
|
||||||
def cisla_rocniku(rocnik, jen_verejne=True):
|
def cisla_rocniku(rocnik, jen_verejne=True):
|
||||||
""" Vrátí všechna čísla daného ročníku.
|
"""
|
||||||
|
Vrátí všechna čísla daného ročníku.
|
||||||
Parametry:
|
Parametry:
|
||||||
rocnik (Rocnik): ročník semináře
|
rocnik (Rocnik): ročník semináře
|
||||||
jen_verejne (bool): zda se mají vrátit jen veřejná, nebo všechna čísla
|
jen_verejne (bool): zda se mají vrátit jen veřejná, nebo všechna čísla
|
||||||
|
@ -538,7 +804,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True):
|
||||||
|
|
||||||
# získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně
|
# získáme body za ročník, seznam obsahuje dvojice (řešitel_id, body) setřízené sestupně
|
||||||
resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele)
|
resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele)
|
||||||
|
|
||||||
# setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší
|
# setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší
|
||||||
setrizeni_resitele_id, setrizeni_resitele, setrizene_body = setrid_resitele_a_body(resitel_rocnikbody_sezn)
|
setrizeni_resitele_id, setrizeni_resitele, setrizene_body = setrid_resitele_a_body(resitel_rocnikbody_sezn)
|
||||||
poradi = sloupec_s_poradim(setrizene_body)
|
poradi = sloupec_s_poradim(setrizene_body)
|
||||||
|
@ -773,6 +1039,7 @@ def vysledkovka_cisla(cislo, context=None):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
class CisloView(generic.DetailView):
|
class CisloView(generic.DetailView):
|
||||||
|
# FIXME zobrazování témátek a vůbec, teď je tam jen odkaz na číslo v pdf
|
||||||
model = Cislo
|
model = Cislo
|
||||||
template_name = 'seminar/archiv/cislo.html'
|
template_name = 'seminar/archiv/cislo.html'
|
||||||
|
|
||||||
|
@ -1308,6 +1575,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):
|
||||||
|
@ -1332,3 +1625,10 @@ def formularOKView(request):
|
||||||
}
|
}
|
||||||
return render(request, template_name, context)
|
return render(request, template_name, context)
|
||||||
|
|
||||||
|
#------------------ Jak řešit - možná má být udělané úplně jinak
|
||||||
|
|
||||||
|
class JakResitView(generic.ListView):
|
||||||
|
template_name = 'seminar/jak-resit.html'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return None
|
||||||
|
|
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,
|
||||||
|
}
|
||||||
|
|
77
seminar/viewsets.py
Normal file
77
seminar/viewsets.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
from rest_framework import viewsets,filters
|
||||||
|
from . import models as m
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
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(viewsets.ModelViewSet):
|
||||||
|
queryset = m.UlohaVzorakNode.objects.all()
|
||||||
|
serializer_class = views.UlohaVzorakNodeSerializer
|
||||||
|
|
||||||
|
class TextViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = m.Text.objects.all()
|
||||||
|
serializer_class = views.TextSerializer
|
||||||
|
|
||||||
|
class TextNodeViewSet(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(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(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)
|
||||||
|
return queryset
|
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>
|
70
vue_frontend/src/components/TreeNodeRoot.vue
Normal file
70
vue_frontend/src/components/TreeNodeRoot.vue
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<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,
|
||||||
|
editorMode: Boolean,
|
||||||
|
debugMode: Boolean,
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
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>
|
74
vue_frontend/src/components/UlohaVzorakNode.vue
Normal file
74
vue_frontend/src/components/UlohaVzorakNode.vue
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<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,
|
||||||
|
},
|
||||||
|
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')
|
28
vue_frontend/src/router/index.js
Normal file
28
vue_frontend/src/router/index.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
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
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
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