Pavel "LEdoian" Turinsky
4 years ago
54 changed files with 10992 additions and 178 deletions
File diff suppressed because one or more lines are too long
@ -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) |
|||
|
@ -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; |
|||
} |
@ -0,0 +1 @@ |
|||
,anet,erebus,25.03.2020 22:21,file:///home/anet/.config/libreoffice/4; |
@ -0,0 +1,7 @@ |
|||
from rest_framework.permissions import BasePermission |
|||
|
|||
class AllowWrite(BasePermission): |
|||
|
|||
def has_permission(self, request, view): |
|||
return request.user.has_perm('auth.org') |
|||
|
After Width: | Height: | Size: 300 KiB |
@ -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'; |
|||
|
|||
} |
@ -0,0 +1,97 @@ |
|||
{% extends "seminar/archiv/base_cisla.html" %} |
|||
|
|||
{# {% block content %} |
|||
<div> |
|||
|
|||
<h1> |
|||
{% block nadpis1a %}{% block nadpis1b %} |
|||
Číslo {{ cislo }} |
|||
{% endblock %}{% endblock %} |
|||
</h1> |
|||
|
|||
{% if cislo.pdf %} |
|||
<p><a href='{{ cislo.pdf.url }}'>Číslo v pdf</a> |
|||
{% endif %} |
|||
<p><a href='{{ cislo.rocnik.verejne_url }}'>Ročník {{ cislo.rocnik }}</a> |
|||
|
|||
{% if v_cisle_zadane %} |
|||
<h2>Zadané problémy</h2> |
|||
<ul> |
|||
{% for p in v_cisle_zadane %} |
|||
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> |
|||
{% if user.is_staff or cislo.verejne %} |
|||
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} |
|||
{% endfor %} |
|||
</ul> |
|||
{% endif %} |
|||
|
|||
{% if resene_problemy %} |
|||
<h2>Řešené problémy</h2> |
|||
<ul> |
|||
{% for p in resene_problemy %} |
|||
<li{% if user.is_staff and not cislo.verejne %} class='mam-org-only'{% endif %}> |
|||
{% if user.is_staff or cislo.verejne %} |
|||
<a href='{{ p.verejne_url }}'>{% endif %}{{ p.kod_v_rocniku }} {{ p.nazev }} {{ p.body_v_zavorce }}{% if user.is_staff or cislo.verejne %}</a>{% endif %} |
|||
{% endfor %} |
|||
</ul> |
|||
{% endif %} |
|||
|
|||
{% if user.is_staff %} |
|||
<div class="mam-org-only"> |
|||
<h2> Orgovské odkazy </h2> |
|||
<ul> |
|||
<li><a href="obalky.pdf">Obálky (PDF)</a></li> |
|||
<li><a href="tituly.tex">Tituly (TeX)</a></li> |
|||
<li><a href="vysledkovka.tex">Výsledkovka (TeX)</a></li> |
|||
<li><a href="obalkovani">Obálkování</a></li> |
|||
</ul> |
|||
</div> |
|||
{% endif %} |
|||
|
|||
{% if cislo.verejna_vysledkovka %} |
|||
<h2>Výsledkovka</h2> |
|||
{% else %} |
|||
{% if user.is_staff %} |
|||
<div class='mam-org-only'> |
|||
<h2>Výsledkovka (neveřejná)</h2> |
|||
{% endif %} |
|||
{% endif %} |
|||
|
|||
{% if cislo.verejna_vysledkovka or user.is_staff %} |
|||
<table class='vysledkovka'> |
|||
<tr class='border-b'> |
|||
<th class='border-r'># |
|||
<th class='border-r'>Jméno #} |
|||
{# problémy by měly být veřejné, když je veřejná výsledkovka #} |
|||
{# {% for p in problemy %} |
|||
<th class='border-r'><a href="{{ p.verejne_url }}">{{ p.kod_v_rocniku }}</a> |
|||
{% endfor %} |
|||
<th class='border-r'>Za číslo</sup> |
|||
<th class='border-r'>Za ročník |
|||
<th class='border-r'>Odjakživa |
|||
{% for rv in radky_vysledkovky %} |
|||
<tr> |
|||
<td class='border-r'>{% autoescape off %}{{ rv.poradi }}{% endautoescape %} |
|||
<th class='border-r'> |
|||
{% if rv.resitel.titul != "" %} |
|||
{{ rv.resitel.titul }}<sup>MM</sup> |
|||
{% endif %} |
|||
{{ rv.resitel.osoba.plne_jmeno }} |
|||
{% for b in rv.hlavni_problemy_body %} |
|||
<td class='border-r'>{{ b }} |
|||
{% endfor %} |
|||
<td class='border-r'>{{ rv.body_cislo }} |
|||
<td class='border-r'><b>{{ rv.body_rocnik }}</b> |
|||
<td class='border-r'>{{ rv.body_celkem_odjakziva }} |
|||
</tr> |
|||
{% endfor %} |
|||
</table> |
|||
{% endif %} |
|||
|
|||
{% if not cislo.verejna_vysledkovka and user.is_staff %} |
|||
</div> |
|||
{% endif %} |
|||
|
|||
</div> |
|||
{% endblock content %} #} |
|||
|
@ -0,0 +1,19 @@ |
|||
{% extends "seminar/archiv/problem.html" %} |
|||
|
|||
{% block problem %} |
|||
<h1> |
|||
{% block nadpis1a %}{% block nadpis1b %} |
|||
{{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }} |
|||
{% endblock %}{% endblock %} |
|||
</h1> |
|||
|
|||
<h2>Zadání</h2> |
|||
{{ problem.text_zadani |safe }} |
|||
{% if problem.text_reseni %} |
|||
<h2>Řešení</h2> |
|||
{{ problem.text_reseni |safe }} |
|||
{% endif %} |
|||
|
|||
{# TODO vysledkovka tematu #} |
|||
|
|||
{% endblock %} |
@ -0,0 +1,23 @@ |
|||
{% extends "seminar/archiv/problem.html" %} |
|||
|
|||
{% block problem %} |
|||
<h1> |
|||
{% block nadpis1a %}{% block nadpis1b %} |
|||
{{ problem.nazev_typu }} {{ problem.kod_v_rocniku }}: {{ problem.nazev }} {{ problem.body_v_zavorce }} |
|||
{% endblock %}{% endblock %} |
|||
</h1> |
|||
{% if problem.cislo_zadani %} |
|||
<p>Zadáno v čísle <a href='{{ problem.cislo_zadani.verejne_url }}'>{{ problem.cislo_zadani.kod }}</a>. |
|||
{% endif %} |
|||
{% if problem.cislo_reseni %} |
|||
<p>Řešeno v čísle <a href='{{ problem.cislo_reseni.verejne_url }}'>{{ problem.cislo_reseni.kod }}</a>. |
|||
{% endif %} |
|||
|
|||
<h2>Zadání</h2> |
|||
{{ problem.text_zadani |safe }} |
|||
{% if problem.text_reseni %} |
|||
<h2>Řešení</h2> |
|||
{{ problem.text_reseni |safe }} |
|||
{% endif %} |
|||
|
|||
{% endblock %} |
@ -0,0 +1,23 @@ |
|||
{% extends "seminar/archiv/base.html" %} |
|||
{% load staticfiles %} |
|||
{% load sekizai_tags %} |
|||
|
|||
{# toto z nejakeho duvodu nefunguje #} |
|||
{% addtoblock css %} |
|||
dfsdfs |
|||
<link rel="stylesheet" type="text/css" href="{% static 'css/mamweb-dev.css' %}" /> |
|||
{% endaddtoblock "css" %} |
|||
|
|||
{% block custom_css %} |
|||
<link rel="stylesheet" type="text/css" href="{% static 'css/mamweb-dev.css' %}" /> |
|||
{% endblock custom_css %} |
|||
|
|||
{% load comments %} |
|||
|
|||
{% block content %} |
|||
<ul> |
|||
{% for obj in object_list %} |
|||
<li>{{obj}} (id {{obj.id}})</li> |
|||
{% endfor %} |
|||
</ul> |
|||
{% endblock content %} |
@ -1,14 +1,54 @@ |
|||
{% extends "base.html" %} |
|||
|
|||
|
|||
{% block content %} |
|||
|
|||
<h2> |
|||
{% block nadpis1a %}{% block nadpis1b %} |
|||
Aktuální témata |
|||
{% endblock %}{% endblock %} |
|||
</h2> |
|||
|
|||
<p>Témata jsou texty nejen z oblasti matematiky, fyziky a informatiky, které popisují nějaký |
|||
problém a jsou doprovázeny návodnými úlohami. Vaším úkolem je zamyslet se nad daným |
|||
problémem a sepsat vaše úvahy ve formě krátkého textu.</p> |
|||
|
|||
<p><a href="/co-je-MaM/jak-resit/">Jak řešit téma?</a></p> |
|||
|
|||
|
|||
<div class="rozcestnik_temat"> |
|||
|
|||
{% for tematko in tematka %} |
|||
<h1>{{tematko.nazev}}</h1> |
|||
<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> |
|||
|
|||
{# karta témátka - zepředu ilustrační, zezadu abstrakt #} |
|||
<div class="tema_pole"> |
|||
|
|||
<h3> |
|||
<a href='{{ rocnik.verejne_url }}'>Téma {{ tematko.nazev }}</a> |
|||
</h3> |
|||
|
|||
<div class="flip-card" id="tema-rozcestnik"> |
|||
|
|||
<div class="flip-card-inner"> |
|||
<div class="flip-card-front"> |
|||
<div class="flip-card-foto"> |
|||
{% if tematko.obrazek %} |
|||
<img src="{{ tematko.obrazek.url }}" alt="{{ tematko.nazev }}"> |
|||
{% else %} {# pokud témátko nemá fotku, zobrazuje se defaultní obrázek #} |
|||
{% load static %} <img src="{% static 'images/tema-bez-obrazku.png' %}" alt="{{ tematko.nazev }}"> |
|||
{% endif %} |
|||
</div> |
|||
</div> |
|||
<div class="flip-card-back"> |
|||
<p>{{ tematko.abstrakt }}</p> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
{# konec karty témátka #} |
|||
{% endfor %} |
|||
|
|||
</div> |
|||
|
|||
{% endblock %} |
|||
|
@ -1,10 +1,12 @@ |
|||
{% extends "base.html" %} |
|||
{% load render_bundle from webpack_loader %} |
|||
|
|||
{% load comments %} |
|||
|
|||
{% 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 %} |
|||
|
@ -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 #} |
@ -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 %} |
|||
{# <b>{{depth}}</b> #} |
|||
<div> |
|||
{% 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|isText %} |
|||
{{obj.node.text.na_web}} |
|||
{% else %} |
|||
Objekt jiného typu {{obj.node}} |
|||
<div class="borderized parent"> |
|||
<div class="node_type"> |
|||
{{obj.node}} |
|||
{{obj.node.id}} |
|||
{% if obj.node|deletable %} |
|||
<button type="submit" formaction="{%url 'treenode_smazat' obj.node.id%}">Smazat</button> |
|||
{% endif %} |
|||
{% if obj.parent and obj.parent|editableSiblings %} |
|||
<button type="submit" formaction="{%url 'treenode_odvesitpryc' obj.node.id%}">Odvěsit pryč ze stromu {{obj.parent.node}}</button> |
|||
{% endif %} |
|||
{% if obj|canPodvesitPred %} |
|||
<button type="submit" formaction="{%url 'treenode_podvesit' obj.node.id 'pred'%}">Podvěsit pod předchozí</button> - nejsou testovací data |
|||
{% endif %} |
|||
{% if obj|canPodvesitZa %} |
|||
<button type="submit" formaction="{%url 'treenode_podvesit' obj.node.id 'za'%}">Podvěsit pod následující</button> - nejsou testovací data |
|||
{% endif %} |
|||
|
|||
|
|||
</div> |
|||
{% if False %} |
|||
<div class="node_move"> |
|||
FIXME: není zatím implementováno |
|||
<button>Zvyš úroveň nadpisu</button> - nejsou testovací data |
|||
</div> |
|||
{% endif %} |
|||
{%if obj.children %} |
|||
<div> |
|||
{% 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 %} |
|||
{%with obj=ch depth=depth|add:"1" template_name="seminar/treenode_recursive.html" %} |
|||
{%include template_name%} |
|||
{%endwith%} |
|||
{%endfor%} |
|||
|
|||
{# ----------- 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> |
|||
{%endif%} |
|||
{% 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> |
|||
|
@ -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,3 +1,4 @@ |
|||
from .views_all import * |
|||
from .autocomplete import * |
|||
from .views_rest import * |
|||
from .odevzdavatko import * |
|||
|
@ -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, |
|||
} |
|||
|
@ -0,0 +1,96 @@ |
|||
from rest_framework import viewsets,filters |
|||
from rest_framework.permissions import BasePermission, AllowAny |
|||
from . import models as m |
|||
from . import views |
|||
|
|||
from seminar.permissions import AllowWrite |
|||
|
|||
class PermissionMixin(object): |
|||
""" Redefines get_permissions so that only organizers can make changes. """ |
|||
|
|||
def get_permissions(self): |
|||
permission_classes = [] |
|||
print("get_permissions have been called.") |
|||
if self.action in ["create", "update", "partial_update", "destroy"]: |
|||
permission_classes = [AllowWrite] # speciální permission na zápis - orgové |
|||
else: |
|||
permission_classes = [AllowAny] |
|||
# návštěvník nemusí být zalogován, aby si prohlížel obsah |
|||
return [permission() for permission in permission_classes] |
|||
|
|||
class ReadWriteSerializerMixin(object): |
|||
""" |
|||
Overrides get_serializer_class to choose the read serializer |
|||
for GET requests and the write serializer for POST requests. |
|||
|
|||
Set read_serializer_class and write_serializer_class attributes on a |
|||
viewset. |
|||
""" |
|||
|
|||
read_serializer_class = None |
|||
create_serializer_class = None |
|||
write_serializer_class = None |
|||
|
|||
def get_serializer_class(self): |
|||
if self.action == "create": |
|||
return self.get_create_serializer_class() |
|||
if self.action in ["update", "partial_update", "destroy"]: |
|||
return self.get_write_serializer_class() |
|||
return self.get_read_serializer_class() |
|||
|
|||
def get_read_serializer_class(self): |
|||
assert self.read_serializer_class is not None, ( |
|||
"'%s' should either include a `read_serializer_class` attribute," |
|||
"or override the `get_read_serializer_class()` method." |
|||
% self.__class__.__name__ |
|||
) |
|||
return self.read_serializer_class |
|||
|
|||
def get_write_serializer_class(self): |
|||
assert self.write_serializer_class is not None, ( |
|||
"'%s' should either include a `write_serializer_class` attribute," |
|||
"or override the `get_write_serializer_class()` method." |
|||
% self.__class__.__name__ |
|||
) |
|||
return self.write_serializer_class |
|||
|
|||
def get_create_serializer_class(self): |
|||
assert self.create_serializer_class is not None, ( |
|||
"'%s' should either include a `create_serializer_class` attribute," |
|||
"or override the `get_create_serializer_class()` method." |
|||
% self.__class__.__name__ |
|||
) |
|||
return self.create_serializer_class |
|||
|
|||
class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet): |
|||
queryset = m.UlohaVzorakNode.objects.all() |
|||
serializer_class = views.UlohaVzorakNodeSerializer |
|||
|
|||
class TextViewSet(PermissionMixin, viewsets.ModelViewSet): |
|||
queryset = m.Text.objects.all() |
|||
serializer_class = views.TextSerializer |
|||
|
|||
class TextNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): |
|||
queryset = m.TextNode.objects.all() |
|||
read_serializer_class = views.TextNodeSerializer |
|||
write_serializer_class = views.TextNodeWriteSerializer |
|||
create_serializer_class = views.TextNodeCreateSerializer |
|||
|
|||
class CastNodeViewSet(PermissionMixin, ReadWriteSerializerMixin,viewsets.ModelViewSet): |
|||
queryset = m.CastNode.objects.all() |
|||
read_serializer_class = views.CastNodeSerializer |
|||
write_serializer_class = views.CastNodeSerializer |
|||
create_serializer_class = views.CastNodeCreateSerializer |
|||
|
|||
class UlohaVzorakNodeViewSet(PermissionMixin, viewsets.ModelViewSet): |
|||
serializer_class = views.UlohaVzorakNodeSerializer |
|||
|
|||
def get_queryset(self): |
|||
queryset = m.UlohaVzorakNode.objects.all() |
|||
nazev = self.request.query_params.get('nazev',None) |
|||
if nazev is not None: |
|||
queryset = queryset.filter(nazev__contains=nazev) |
|||
if self.request.user.has_perm('auth.org'): |
|||
return queryset |
|||
else: # pro neorgy jen zveřejněné vzoráky |
|||
return queryset.filter(uloha__cislo_reseni__verejne_db=True) |
@ -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? |
@ -0,0 +1,5 @@ |
|||
module.exports = { |
|||
presets: [ |
|||
'@vue/cli-plugin-babel/preset' |
|||
] |
|||
} |
@ -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" |
|||
] |
|||
} |
@ -0,0 +1,7 @@ |
|||
<template> |
|||
<router-view id="app"/> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { name: 'app' } |
|||
</script> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -0,0 +1,75 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<div id="loading" v-if="loading"> |
|||
Loading... |
|||
</div> |
|||
<!--pre> |
|||
{{item}} |
|||
</pre--> |
|||
<button v-show="editorMode" v-on:click="editorMode = false">Vypnout editační mód</button> |
|||
<button v-show="!editorMode" v-on:click="editorMode = true">Zapnout editační mód</button> |
|||
<button v-show="debugMode" v-on:click="debugMode = false">Vypnout ladicí mód</button> |
|||
<button v-show="!debugMode" v-on:click="debugMode = true">Zapnout ladicí mód</button> |
|||
<TreeNode :item="item" :editorMode="editorMode" :debugMode="debugMode"/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import TreeNode from './TreeNode.vue' |
|||
import axios from 'axios' |
|||
export default { |
|||
name: 'App', |
|||
components: { |
|||
TreeNode, |
|||
}, |
|||
data: () => ({ |
|||
loading: true, |
|||
item: null, |
|||
tnid: 1, |
|||
editorMode: false, |
|||
debugMode: false, |
|||
}), |
|||
props:{ |
|||
tnid: Number, |
|||
tnsource: String, |
|||
editorMode: Boolean, |
|||
debugMode: Boolean, |
|||
}, |
|||
mounted: function() { |
|||
if (this.tnsource && this.tnsource=='inline'){ |
|||
let data = JSON.parse(document.getElementById('vuedata').textContent); |
|||
this.tnid = data.treenode; |
|||
} |
|||
this.getArticles(); |
|||
this.$root.$on('updateData',(arg) => { |
|||
console.log(arg); |
|||
this.getArticles(); |
|||
}); |
|||
}, |
|||
methods: { |
|||
getArticles: function() { |
|||
this.loading = true; |
|||
axios.get('/treenode/'+this.tnid+'/json/') |
|||
.then((response) => { |
|||
this.item = response.data; |
|||
this.loading = false; |
|||
console.log('Data updated'); |
|||
this.$root.$emit('dataUpdated',"dataUpdated"); |
|||
}) |
|||
.catch((err) => { |
|||
this.loading = false; |
|||
console.log(err); |
|||
}) |
|||
} |
|||
}, |
|||
events: { |
|||
updateData: function(){ |
|||
this.getArticles() |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
@import '../../../mamweb/static/css/mamweb.css'; |
|||
</style> |
@ -0,0 +1,75 @@ |
|||
<template> |
|||
<div class="ulohavzoraknode"> |
|||
<!--pre>UlohaVzorakNode {{item}} {{typeof(item)}}</pre--> |
|||
<h5>Řešení {{item.node.uloha.cislo_zadani.poradi}}.{{ item.node.uloha.kod }}: {{ item.node.uloha.nazev }}</h5> |
|||
<button v-if="editorMode" v-on:click="showSelect=!showSelect" class="upravit">Upravit</button> |
|||
<div v-if="showSelect"> |
|||
<form class="searchForm" v-on:submit.prevent="submitSearch"> |
|||
<input type="text" v-model="searchQuery" placeholder="Napište název" @keyup="submitSearch"> |
|||
</form> |
|||
<div class="searchResult" v-show="isResult"> |
|||
<ul> |
|||
<li v-for="res in searchResults" :key="res.id" v-on:click="setSelected(res)">{{res.nazev}}</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import axios from 'axios' |
|||
|
|||
export default { |
|||
name: 'UlohaVzorakNode', |
|||
data: () => { |
|||
return { |
|||
isResult: false, |
|||
searchQuery: '', |
|||
searchResults: [], |
|||
showSelect: false, |
|||
selected: null, |
|||
selected_id: null |
|||
} |
|||
}, |
|||
props: { |
|||
item: Object, |
|||
create: Boolean, |
|||
showSelect: Boolean, |
|||
editorMode: Boolean, |
|||
}, |
|||
mounted: function(){ |
|||
if (this.item.node.uloha === null){ |
|||
console.log("Uloha je null!"); |
|||
console.log(this.item); |
|||
} |
|||
if (this.create){ |
|||
this.showSelect = true; |
|||
console.log('Creating'); |
|||
} |
|||
}, |
|||
methods: { |
|||
submitSearch: function(){ |
|||
if (this.searchQuery.length < 3) { return;} |
|||
var reqURL = "/api/ulohavzoraknode/?nazev="+this.searchQuery; |
|||
axios.get(reqURL).then( (response) => { |
|||
this.searchResults = response.data.results; |
|||
this.isResult = true; |
|||
console.log("Got:"); |
|||
console.log(this.searchResults); |
|||
}).catch( (err) => { /* fail response msg */ |
|||
console.log(err); |
|||
}); |
|||
}, |
|||
setSelected: function(res){ |
|||
this.searchQuery = res.nazev |
|||
this.selected_id = res.id |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.upravit { |
|||
margin-top:-40px; |
|||
} |
|||
</style> |
@ -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> |
@ -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') |
@ -0,0 +1,33 @@ |
|||
import Vue from 'vue' |
|||
import Router from 'vue-router' |
|||
import TreeNodeRoot from '../components/TreeNodeRoot.vue' |
|||
|
|||
Vue.use(Router) |
|||
|
|||
export default new Router({ |
|||
mode: 'history', |
|||
linkActiveClass: 'active', |
|||
routes: [{ |
|||
path: '/temp/vue', |
|||
name: 'treenodedefault', |
|||
props: {'tnid': 23}, |
|||
component: TreeNodeRoot |
|||
}, { |
|||
path: '/temp/vue/:tnid', |
|||
name: 'treenode', |
|||
props: true, |
|||
component: TreeNodeRoot |
|||
}, { |
|||
path: '/zadani/aktualni', |
|||
name: 'treenode_zadani', |
|||
props: {'tnid': 23}, |
|||
component: TreeNodeRoot |
|||
}, { |
|||
path: '/cislo/:cislo', |
|||
name: 'treenode_cislo', |
|||
props: {'tnsource':'inline'}, |
|||
component: TreeNodeRoot |
|||
} |
|||
] |
|||
}) |
|||
|
@ -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": ["*"]}) |
|||
|
|||
} |
|||
}; |
File diff suppressed because it is too large
Loading…
Reference in new issue