Commit 41e8f35bc94668dc4ebf5d6d8620241d14a91684

Authored by Katarzyna Krasnowska
1 parent 9632de87

added prototype phrase expansions page

locale/en/LC_MESSAGES/django.mo
No preview for this file type
locale/en/LC_MESSAGES/django.po
... ... @@ -8,7 +8,7 @@ msgid ""
8 8 msgstr ""
9 9 "Project-Id-Version: PACKAGE VERSION\n"
10 10 "Report-Msgid-Bugs-To: \n"
11   -"POT-Creation-Date: 2020-11-09 11:31+0100\n"
  11 +"POT-Creation-Date: 2020-11-13 12:05+0100\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
... ... @@ -348,7 +348,7 @@ msgstr &quot; with possible realisations: &quot;
348 348 #: entries/phrase_descriptions/descriptions.py:225
349 349 #, python-brace-format
350 350 msgid "frazeologizm w postaci {phrase} zamrożony w postaci <i>{phraseo}</i>"
351   -msgstr "a phraseologizm {phrase} frozen in the form <i>{phraseo}</i>"
  351 +msgstr "{phrase} phraseologism frozen in the form <i>{phraseo}</i>"
352 352  
353 353 #: entries/phrase_descriptions/polish_strings.py:9
354 354 #: entries/phrase_descriptions/polish_strings.py:336
... ... @@ -1826,25 +1826,38 @@ msgstr &quot;Source&quot;
1826 1826 msgid "Brak przykładów"
1827 1827 msgstr "No examples"
1828 1828  
1829   -#: phrase_expansions/templates/phrase_expansions.html:17
1830   -msgid "advp (frazy przysłówkowe)"
1831   -msgstr "advp (adverbial phrases)"
  1829 +#: phrase_expansions/views.py:11
  1830 +msgid "potoczne"
  1831 +msgstr "colloquial"
  1832 +
  1833 +#: phrase_expansions/views.py:12
  1834 +msgid "archaiczne"
  1835 +msgstr "archaic"
  1836 +
  1837 +#: phrase_expansions/views.py:13
  1838 +msgid "wątpliwe"
  1839 +msgstr "uncertain"
  1840 +
  1841 +#: phrase_expansions/views.py:14
  1842 +msgid "pewne"
  1843 +msgstr "certain"
  1844 +
  1845 +#: phrase_expansions/views.py:49
  1846 +msgid "frazy przysłówkowe"
  1847 +msgstr "adverbial phrases"
1832 1848  
1833   -#: phrase_expansions/templates/phrase_expansions.html:17
1834   -#: phrase_expansions/templates/phrase_expansions.html:32
1835   -#: phrase_expansions/templates/phrase_expansions.html:47
1836   -#: phrase_expansions/templates/phrase_expansions.html:62
1837   -msgid "rozwiń"
1838   -msgstr "expand"
  1849 +#: phrase_expansions/views.py:50
  1850 +msgid "frazy okolicznikowe"
  1851 +msgstr "adjunct phrases"
1839 1852  
1840   -#: phrase_expansions/templates/phrase_expansions.html:32
1841   -msgid "xp (frazy okolicznikowe)"
1842   -msgstr "xp (adjunct phrases)"
  1853 +#: phrase_expansions/views.py:51
  1854 +msgid "frazy przyimkowe z przyimkiem złożonym"
  1855 +msgstr "prepositional phrases with complex preposition"
1843 1856  
1844   -#: phrase_expansions/templates/phrase_expansions.html:47
1845   -msgid "comprepnp (frazy przyimkowe z przyimkiem złożonym)"
1846   -msgstr "comprepnp (prepositional phrases with complex preposition)"
  1857 +#: phrase_expansions/views.py:52
  1858 +msgid "fraza dystrybutywna"
  1859 +msgstr "distributive phrase"
1847 1860  
1848   -#: phrase_expansions/templates/phrase_expansions.html:62
1849   -msgid "pozostałe frazy"
1850   -msgstr "other phrases"
  1861 +#: phrase_expansions/views.py:53
  1862 +msgid "fraza posesywna"
  1863 +msgstr "possesive phrase"
... ...
locale/en/LC_MESSAGES/djangojs.po
... ... @@ -8,7 +8,7 @@ msgid &quot;&quot;
8 8 msgstr ""
9 9 "Project-Id-Version: PACKAGE VERSION\n"
10 10 "Report-Msgid-Bugs-To: \n"
11   -"POT-Creation-Date: 2020-11-09 11:31+0100\n"
  11 +"POT-Creation-Date: 2020-11-13 12:05+0100\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
... ... @@ -48,50 +48,50 @@ msgstr &quot;Remove&quot;
48 48 msgid "Opinia"
49 49 msgstr "Opinion"
50 50  
51   -#: entries/static/entries/js/entries.js:325
  51 +#: entries/static/entries/js/entries.js:326
52 52 #: entries/static/entries/js/entries2.js:331
53 53 msgid "Funkcja"
54 54 msgstr "Function"
55 55  
56   -#: entries/static/entries/js/entries.js:328
  56 +#: entries/static/entries/js/entries.js:329
57 57 #: entries/static/entries/js/entries2.js:334
58 58 msgid "Typy fraz"
59 59 msgstr "Phrase types"
60 60  
61   -#: entries/static/entries/js/entries.js:385
  61 +#: entries/static/entries/js/entries.js:386
62 62 #: entries/static/entries/js/entries2.js:394
63 63 msgid "brak schematów"
64 64 msgstr "no schemata"
65 65  
66   -#: entries/static/entries/js/entries.js:409
  66 +#: entries/static/entries/js/entries.js:411
67 67 msgid "nowa jednostka spoza <i>Słowosieci</i>"
68 68 msgstr "new lexical unit not in <i>plWordnet</i>"
69 69  
70   -#: entries/static/entries/js/entries.js:415
  70 +#: entries/static/entries/js/entries.js:418
71 71 msgid "Przejdź do strony tej jednostki w <i>Słowosieci</i>"
72 72 msgstr "Go to this lexical unit’s <i>plWordnet</i> page"
73 73  
74   -#: entries/static/entries/js/entries.js:431
  74 +#: entries/static/entries/js/entries.js:434
75 75 #: entries/static/entries/js/entries2.js:412
76 76 msgid "Rola"
77 77 msgstr "Role"
78 78  
79   -#: entries/static/entries/js/entries.js:433
  79 +#: entries/static/entries/js/entries.js:436
80 80 #: entries/static/entries/js/entries2.js:414
81 81 msgid "Preferencje selekcyjne"
82 82 msgstr "Selectional preferences"
83 83  
84   -#: entries/static/entries/js/entries.js:466
  84 +#: entries/static/entries/js/entries.js:469
85 85 #: entries/static/entries/js/entries2.js:450
86 86 msgid "brak ram"
87 87 msgstr "no frames"
88 88  
89   -#: entries/static/entries/js/entries.js:483
  89 +#: entries/static/entries/js/entries.js:486
90 90 #: entries/static/entries/js/entries2.js:467
91 91 msgid "Kliknij, aby wyświetlić przykłady dla tego schematu."
92 92 msgstr "Click to show examples for this schema."
93 93  
94   -#: entries/static/entries/js/entries.js:538
  94 +#: entries/static/entries/js/entries.js:541
95 95 #: entries/static/entries/js/entries2.js:517
96 96 msgid ""
97 97 "Kliknij, aby wyświetlić przykłady dla tej ramy oraz jej realizacje "
... ... @@ -99,63 +99,63 @@ msgid &quot;&quot;
99 99 msgstr ""
100 100 "Click to show examples linked to this frame and its syntactic realisations."
101 101  
102   -#: entries/static/entries/js/entries.js:604
  102 +#: entries/static/entries/js/entries.js:612
103 103 msgid ""
104 104 "Kliknij, aby cofnąć ograniczenie wyświetlanych przykładów do powiązanych z "
105 105 "tym znaczeniem."
106 106 msgstr "Click to undo restriction to examples linked to this meaning."
107 107  
108   -#: entries/static/entries/js/entries.js:606
  108 +#: entries/static/entries/js/entries.js:614
109 109 msgid "Kliknij, aby wyświetlić wyłącznie przykłady powiązane z tym znaczeniem."
110 110 msgstr "Click to show only examples linked to this meaning."
111 111  
112   -#: entries/static/entries/js/entries.js:636
  112 +#: entries/static/entries/js/entries.js:644
113 113 #: entries/static/entries/js/entries2.js:578
114 114 msgid ""
115 115 "Kliknij, aby cofnąć ograniczenie wyświetlanych przykładów do powiązanych z "
116 116 "tą rolą."
117 117 msgstr "Click to undo restriction to examples linked to this role."
118 118  
119   -#: entries/static/entries/js/entries.js:638
  119 +#: entries/static/entries/js/entries.js:646
120 120 #: entries/static/entries/js/entries2.js:580
121 121 msgid "Kliknij, aby wyświetlić wyłącznie przykłady powiązane z tą rolą."
122 122 msgstr "Click to show only examples linked to this role."
123 123  
124   -#: entries/static/entries/js/entries.js:676
  124 +#: entries/static/entries/js/entries.js:684
125 125 #: entries/static/entries/js/entries2.js:616
126 126 msgid ""
127 127 "Kliknij, aby cofnąć ograniczenie wyświetlanych przykładów do powiązanych z "
128 128 "tym schematem."
129 129 msgstr "Click to undo restriction to examples linked to this schema."
130 130  
131   -#: entries/static/entries/js/entries.js:678
  131 +#: entries/static/entries/js/entries.js:686
132 132 #: entries/static/entries/js/entries2.js:618
133 133 msgid "Kliknij, aby wyświetlić wyłącznie przykłady powiązane z tym schematem."
134 134 msgstr "Click to show only examples linked to this schema."
135 135  
136   -#: entries/static/entries/js/entries.js:706
  136 +#: entries/static/entries/js/entries.js:714
137 137 #: entries/static/entries/js/entries2.js:647
138 138 msgid "Kliknij, aby cofnąć wybór tej ramy."
139 139 msgstr "Click to undo choice if this frame."
140 140  
141   -#: entries/static/entries/js/entries.js:794
  141 +#: entries/static/entries/js/entries.js:802
142 142 #: entries/static/entries/js/entries2.js:725
143 143 msgid "Komentarz"
144 144 msgstr "Comment"
145 145  
146   -#: entries/static/entries/js/entries.js:802
  146 +#: entries/static/entries/js/entries.js:810
147 147 #: entries/static/entries/js/entries2.js:733
148 148 msgid ""
149 149 "Kliknij, aby cofnąć wyświetlanie argumentów i fraz powiązanych z tym "
150 150 "przykładem."
151 151 msgstr "Click to undo showing arguments and phrases linked to this example."
152 152  
153   -#: entries/static/entries/js/entries.js:804
  153 +#: entries/static/entries/js/entries.js:812
154 154 #: entries/static/entries/js/entries2.js:735
155 155 msgid "Kliknij, aby wyświetlić argumenty i frazy powiązane z tym przykładem."
156 156 msgstr "Click to show arguments and phrases linked to this example."
157 157  
158   -#: entries/static/entries/js/entries.js:884
  158 +#: entries/static/entries/js/entries.js:892
159 159 #: entries/static/entries/js/entries2.js:815
160 160 msgid "brak haseł"
161 161 msgstr "no entries"
... ...
phrase_expansions/admin.py
1 1 from django.contrib import admin
2 2  
3   -# Register your models here.
  3 +from .models import ExpansionOpinion, PhraseExpansionType, PhraseExpansion, ExpansionPosition, ExpansionPhrase, ExpansionPhraseDescription
  4 +
  5 +admin.site.register(ExpansionOpinion)
  6 +admin.site.register(PhraseExpansionType)
  7 +admin.site.register(PhraseExpansion)
  8 +admin.site.register(ExpansionPosition)
  9 +admin.site.register(ExpansionPhrase)
  10 +admin.site.register(ExpansionPhraseDescription)
... ...
phrase_expansions/management/commands/import_expansions.py 0 → 100644
  1 +import os
  2 +
  3 +from xml.sax import handler, make_parser
  4 +
  5 +from django.core.management.base import BaseCommand
  6 +
  7 +from importer.Phrase import phrase_from_tree
  8 +from importer.Position import Position
  9 +from importer.WalentyXML import XMLNode
  10 +from shellvalier.settings import BASE_DIR
  11 +
  12 +from phrase_expansions.models import ExpansionOpinion, PhraseExpansionType, PhraseExpansion, ExpansionPosition, ExpansionPhrase, ExpansionPhraseDescription
  13 +
  14 +from entries.phrase_descriptions.descriptions import phrase_description2
  15 +
  16 +class Command(BaseCommand):
  17 + args = 'none'
  18 + help = ''
  19 +
  20 + def handle(self, **options):
  21 + import_expansions()
  22 +
  23 +OPINION_MAP = {
  24 + 'archaiczna' : 'dat',
  25 + 'pewna' : 'cer',
  26 + 'potoczna' : 'col',
  27 + 'wątpliwa' : 'unc',
  28 +}
  29 +
  30 +def import_expansions():
  31 + xml_file = os.path.join(BASE_DIR, 'data', 'walenty', 'phrase_types_expand_20200926.xml')
  32 + xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), xml_file)
  33 +
  34 + parser = make_parser()
  35 +
  36 + parser.setContentHandler(ExpansionsTeiHandler())
  37 + parser.parse(xml_path)
  38 +
  39 + expansions = parser.getContentHandler()._expansions
  40 +
  41 + for cls in (ExpansionOpinion, PhraseExpansion, ExpansionPosition, ExpansionPhrase, ExpansionPhraseDescription):
  42 + cls.objects.all().delete()
  43 +
  44 + opinions = [(50, u'col'), (40, u'dat'), (20, u'unc'), (10, u'cer'),]
  45 + for pri, short in opinions:
  46 + opinion = ExpansionOpinion(key=short, priority=pri)
  47 + opinion.save()
  48 +
  49 + for (phrase_type, phrase_subtype), exps in expansions.items():
  50 + expansion_type = PhraseExpansionType.objects.create(phrase_type=phrase_type,
  51 + phrase_subtype=phrase_subtype)
  52 + expansion_type.save()
  53 + print(expansion_type)
  54 + for i, (positions, opinion) in enumerate(exps):
  55 + opinion = ExpansionOpinion.objects.get(key=OPINION_MAP[opinion])
  56 + expansion = PhraseExpansion.objects.create(expansion_type=expansion_type,
  57 + opinion=opinion,
  58 + priority=(i + 1))
  59 + expansion.save()
  60 + expansion_type.max_positions = max(expansion_type.max_positions, len(positions))
  61 + for j, pos in enumerate(positions):
  62 + position = ExpansionPosition(expansion=expansion, priority=(j + 1))
  63 + position.save()
  64 + for k, (text_rep, desc_pl, desc_en) in enumerate(pos):
  65 + phrase = ExpansionPhrase(position=position, text_rep=text_rep)
  66 + phrase.save()
  67 + d_pl = ExpansionPhraseDescription(phrase=phrase, lang='pl', description=desc_pl)
  68 + d_en = ExpansionPhraseDescription(phrase=phrase, lang='en', description=desc_en)
  69 + d_pl.save()
  70 + d_en.save()
  71 + expansion_type.save()
  72 + print(sum(map(len, expansions.values())))
  73 +
  74 +class ExpansionsTeiHandler(handler.ContentHandler):
  75 +
  76 + def __init__(self):
  77 + handler.ContentHandler.__init__(self)
  78 + self._subtree = None
  79 + self._current = None
  80 + self._constructing = False
  81 + self._content = ""
  82 + self._expansions = dict()
  83 +
  84 + def startElement(self, name, attrs):
  85 + if name == 'entry':
  86 + self._constructing = True
  87 + self._content = ""
  88 + if (self._constructing):
  89 + node = XMLNode(name, attrs, self._current)
  90 + if self._current is not None:
  91 + self._current.addChild(node)
  92 + else:
  93 + self._subtree = node
  94 + self._current = node
  95 +
  96 + def endElement(self, name):
  97 + if self._current is not None:
  98 + self._current.setContent(self._content.strip())
  99 + self._current = self._current._parent
  100 + if name == 'entry':
  101 + if self._current is not None:
  102 + raise TEIStructureError()
  103 + typ = self._subtree._children[0]._attrs['type']
  104 + self.get_expansions(self._subtree, typ)
  105 + self._content = ''
  106 +
  107 + def characters(self, content):
  108 + self._content += content
  109 +
  110 + def get_expansions(self, tree, phrase_type):
  111 + dummy_position = Position(None, None, None, None, None)
  112 + if phrase_type == 'advp':
  113 + subtype = tree._children[0]._children[0]._children[0]._attrs['value']
  114 + elif phrase_type == 'xp':
  115 + subtype = tree._children[0]._children[0]._children[0]._children[0]._children[0]._attrs['value']
  116 + elif phrase_type == 'comprepnp':
  117 + subtype = tree._children[0]._children[0]._children[0]._content
  118 + elif phrase_type in ('distrp', 'possp'):
  119 + subtype = None
  120 + #print('{}({})'.format(phrase_type, subtype))
  121 + assert((phrase_type, subtype) not in self._expansions)
  122 + expansions = []
  123 + for exp in tree._children[1]._children[0]._children:
  124 + expansion_positions = []
  125 + opinion = exp._children[0]._children[0]._attrs['value']
  126 + if exp._children[1]._attrs['name'] == 'phrases':
  127 + positions = [exp._children[1]]
  128 + elif exp._children[1]._attrs['name'] == 'positions':
  129 + positions = [pos._children[0] for pos in exp._children[1]._children[0]._children]
  130 + for position in positions:
  131 + expansion_position = []
  132 + for phrase in position._children[0]._children:
  133 + typ = phrase._attrs['type']
  134 + if typ == 'adverb':
  135 + adverb = phrase._children[0]._children[0]._attrs['value']
  136 + expansion_position.append((adverb, 'przysłówek <i>{}</i>'.format(adverb), '<i>{}</i> adverb'.format(adverb)))
  137 + elif typ == 'advp':
  138 + # xp realised by advp(cat)
  139 + advpcat = phrase._children[-1]._children[0]._attrs['value']
  140 + expansion_position.append(('advp({})'.format(advpcat), '???', '???'))
  141 + elif typ == 'comprepnp':
  142 + prep = phrase._children[1]._children[0]._content
  143 + expansion_position.append(('comprepnp({})'.format(prep), 'fraza rzeczownikowo-przyimkowa z przyimkiem złożonym <i>{}</i>'.format(prep), 'nominal-prepositional phrase with <i>{}</i> complex preposition'.format(prep)))
  144 + else:
  145 + phr = phrase_from_tree(phrase)
  146 + if False:#str(phr) == 'lex(adjp(agr),agr,agr,pos,OR(cudzy;czyj;czyjkolwiek;czyjś;mój;nasz;niczyj;pański;swój;twój;wasz),natr)':
  147 + desc_pl, desc_en = None, None
  148 + else:
  149 + desc_pl, desc_en = phrase_description2(phr, dummy_position, None, 'pl'), phrase_description2(phr, dummy_position, None, 'en')
  150 + expansion_position.append((str(phr), desc_pl, desc_en))
  151 + expansion_positions.append(expansion_position)
  152 + assert(expansion_positions)
  153 + expansions.append((expansion_positions, opinion))
  154 + self._expansions[(phrase_type, subtype)] = expansions
... ...
phrase_expansions/models.py
1 1 from django.db import models
2 2  
3   -# Create your models here.
  3 +
  4 +class ExpansionOpinion(models.Model):
  5 + key = models.CharField(max_length=16, unique=True)
  6 + priority = models.PositiveIntegerField()
  7 +
  8 + class Meta:
  9 + ordering = ['priority']
  10 +
  11 + def __str__(self):
  12 + return self.key
  13 +
  14 +class PhraseExpansionType(models.Model):
  15 + phrase_type = models.CharField(max_length=16)
  16 + phrase_subtype = models.CharField(max_length=32, null=True)
  17 + max_positions = models.PositiveIntegerField(default=1)
  18 +
  19 + class Meta:
  20 + ordering = ['phrase_type', 'phrase_subtype']
  21 +
  22 + def __str__(self):
  23 + return '{}({})'.format(self.phrase_type, self.phrase_subtype) if self.phrase_subtype else self.phrase_type
  24 +
  25 +class PhraseExpansion(models.Model):
  26 + expansion_type = models.ForeignKey(PhraseExpansionType, on_delete=models.PROTECT, related_name='expansions')
  27 + opinion = models.ForeignKey(ExpansionOpinion, on_delete=models.PROTECT)
  28 + priority = models.PositiveIntegerField()
  29 +
  30 + class Meta:
  31 + ordering = ['priority']
  32 +
  33 + def __str__(self):
  34 + return '{}: {}'.format(self.opinion, ' + '.join([str(pos) for pos in self.positions.all()]))
  35 +
  36 +class ExpansionPosition(models.Model):
  37 + expansion = models.ForeignKey(PhraseExpansion, on_delete=models.PROTECT, related_name='positions')
  38 + priority = models.PositiveIntegerField()
  39 +
  40 + class Meta:
  41 + ordering = ['priority']
  42 +
  43 + def __str__(self):
  44 + return '{%s}' % (';'.join([str(pt) for pt in self.phrases.all()]))
  45 +
  46 +class ExpansionPhrase(models.Model):
  47 + position = models.ForeignKey(ExpansionPosition, on_delete=models.PROTECT, related_name='phrases')
  48 + text_rep = models.TextField()
  49 +
  50 + class Meta:
  51 + ordering = ['text_rep']
  52 +
  53 + def __str__(self):
  54 + return self.text_rep
  55 +
  56 +class ExpansionPhraseDescription(models.Model):
  57 + phrase = models.ForeignKey(ExpansionPhrase, on_delete=models.PROTECT, related_name='descriptions')
  58 + lang = models.CharField(max_length=2, choices=[('pl', 'pl'), ('en', 'en')])
  59 + description = models.TextField(null=True)
... ...
phrase_expansions/static/phrase_expansions/js/expansions.js 0 → 100644
  1 +"use strict";
  2 +
  3 +$(document).ready(function() {
  4 +
  5 + $('[data-toggle="tooltip"]').tooltip();
  6 +
  7 + $('.collapse').on('show.bs.collapse', function() {
  8 + $('a[href="#' + $(this).attr('id') + '"]').find('.action').html('-');
  9 + }).on('hide.bs.collapse', function() {
  10 + $('a[href="#' + $(this).attr('id') + '"]').find('.action').html('+');
  11 + })
  12 +
  13 +});
... ...
phrase_expansions/templates/phrase_expansions.html
... ... @@ -6,68 +6,92 @@
6 6 {% block title %}{% endblock %}
7 7  
8 8 {% block scripts %}
  9 + <script src="{% static 'phrase_expansions/js/expansions.js' %}"></script>
9 10 {% endblock %}
10 11  
11 12 {% block content2 %}
12 13  
13   -<div class="card mt-3">
14   - <div class="card-header" id="heading-advp">
15   - <h2 class="mb-0">
16   - <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#advp" aria-expanded="false" aria-controls="advp">
17   - {% trans "advp (frazy przysłówkowe)" %}&nbsp;&nbsp;&nbsp;&nbsp;[<span class="action">{% trans "rozwiń" %}</span>]
18   - </button>
19   - </h2>
20   - </div>
21   - <div id="advp" class="collapse" aria-labelledby="heading-advp">
22   - <div class="card-body">
23   - ...
24   - </div>
25   - </div>
26   -</div>
  14 +<div class="accordion my-3" id="accordion">
27 15  
28   -<div class="card mt-3">
29   - <div class="card-header" id="heading-xp">
30   - <h2 class="mb-0">
31   - <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#xp" aria-expanded="false" aria-controls="xp">
32   - {% trans "xp (frazy okolicznikowe)" %}&nbsp;&nbsp;&nbsp;&nbsp;[<span class="action">{% trans "rozwiń" %}</span>]
33   - </button>
34   - </h2>
35   - </div>
36   - <div id="xp" class="collapse" aria-labelledby="heading-xp">
37   - <div class="card-body">
38   - ...
39   - </div>
40   - </div>
41   -</div>
  16 +{% for phrase_expansions in expansions %}
42 17  
43   -<div class="card mt-3">
44   - <div class="card-header" id="heading-comprepnp">
45   - <h2 class="mb-0">
46   - <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#comprepnp" aria-expanded="false" aria-controls="comprepnp">
47   - {% trans "comprepnp (frazy przyimkowe z przyimkiem złożonym)" %}&nbsp;&nbsp;&nbsp;&nbsp;[<span class="action">{% trans "rozwiń" %}</span>]
48   - </button>
49   - </h2>
  18 +<div class="card">
  19 + <div class="card-header p-3" id="heading-{{ phrase_expansions.phrase_type }}">
  20 + <h5 class="mb-0">
  21 + <a data-toggle="collapse" href="#{{ phrase_expansions.phrase_type }}" role="button" aria-expanded="false" aria-controls="{{ phrase_expansions.phrase_type }}">
  22 + {{ phrase_expansions.title }}<span class="float-right">[<span class="action">+</span>]</span>
  23 + </a>
  24 + </h5>
50 25 </div>
51   - <div id="comprepnp" class="collapse" aria-labelledby="heading-comprepnp">
  26 + <div id="{{ phrase_expansions.phrase_type }}" class="collapse" aria-labelledby="heading-{{ phrase_expansions.phrase_type }}" data-parent="#accordion">
52 27 <div class="card-body">
53   - ...
  28 + {% if phrase_expansions.phrase_subtypes|length > 1 and phrase_expansions.phrase_type != 'comprepnp' %}
  29 + <div class="accordion" id="accordion-{{ phrase_expansions.phrase_type }}">
  30 + {% endif %}
  31 + {% for subtype_expansions in phrase_expansions.phrase_subtypes %}
  32 + {% if phrase_expansions.phrase_subtypes|length > 1 and phrase_expansions.phrase_type != 'comprepnp' %}
  33 + <div class="card">
  34 + <div class="card-header p-2" id="heading-{{ phrase_expansions.phrase_type }}-{{ subtype_expansions.phrase_subtype|slugify }}">
  35 + <h6 class="mb-0">
  36 + <a data-toggle="collapse" href="#{{ phrase_expansions.phrase_type }}-{{ subtype_expansions.phrase_subtype|slugify }}" role="button" aria-expanded="false" aria-controls="{{ phrase_expansions.phrase_type }}-{{ subtype_expansions.phrase_subtype|slugify }}">
  37 + {{ subtype_expansions.title }}<span class="float-right">[<span class="action">+</span>]</span>
  38 + </a>
  39 + </h6>
  40 + </div>
  41 + <div
  42 + id="{{ phrase_expansions.phrase_type }}-{{ subtype_expansions.phrase_subtype|slugify }}"
  43 + class="collapse"
  44 + aria-labelledby="heading-{{ phrase_expansions.phrase_type }}-{{ subtype_expansions.phrase_subtype|slugify }}"
  45 + data-parent="#accordion-{{ phrase_expansions.phrase_type }}"
  46 + >
  47 + <div class="card-body">
  48 + {% endif %}
  49 + <table class="table table-sm table-borderless border border-secondary text-dark mb-1">
  50 + <tbody>
  51 + {% for expansion in subtype_expansions.expansions %}
  52 + <tr>
  53 + {% if phrase_expansions.phrase_type == 'comprepnp' and forloop.counter == 1 %}
  54 + <th class="py-2 px-1" style="width: 13em;" scope="row" rowspan="{{ subtype_expansions.expansions|length }}">
  55 + {{ subtype_expansions.phrase_subtype }}
  56 + </th>
  57 + {% endif %}
  58 + <td class="py-2 px-1" style="width: 7em;"><img src="/static/entries/img/{{ expansion.opinion_sym }}.svg" alt="{{ expansion.opinion_str }}" width="12" height="12">
  59 + {{ expansion.opinion_str }}
  60 + </td>
  61 + {% for position in expansion.positions %}
  62 + <td class="px-0 py-0 border-top border-left border-secondary text-break">
  63 + {% for phrase in position.phrases %}
  64 + <div class="phrase px-1 py-2{% if forloop.counter > 1 %} border-top{% endif %}">
  65 + {% if phrase.desc %}
  66 + <span data-toggle="tooltip" data-placement="bottom" data-html="true" title="{{ phrase.desc }}">
  67 + {{ phrase.str }}
  68 + </span>
  69 + {% else %}
  70 + {{ phrase.str }}
  71 + {% endif %}
  72 + </div>
  73 + {% endfor %}
  74 + </td>
  75 + {% endfor %}
  76 + </tr>
  77 + {% endfor %}
  78 + </tbody>
  79 + </table>
  80 + {% if phrase_expansions.phrase_subtypes|length > 1 and phrase_expansions.phrase_type != 'comprepnp' %}
  81 + </div>
  82 + </div>
  83 + </div>
  84 + {% endif %}
  85 + {% endfor %}
  86 + {% if phrase_expansions.phrase_subtypes|length > 1 and phrase_expansions.phrase_type != 'comprepnp' %}
  87 + </div><!-- accordion -->
  88 + {% endif %}
54 89 </div>
55 90 </div>
56 91 </div>
57 92  
58   -<div class="card mt-4">
59   - <div class="card-header" id="heading-other">
60   - <h2 class="mb-0">
61   - <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#other" aria-expanded="false" aria-controls="other">
62   - {% trans "pozostałe frazy" %}&nbsp;&nbsp;&nbsp;&nbsp;[<span class="action">{% trans "rozwiń" %}</span>]
63   - </button>
64   - </h2>
65   - </div>
66   - <div id="other" class="collapse" aria-labelledby="heading-other">
67   - <div class="card-body">
68   - ...
69   - </div>
70   - </div>
  93 +{% endfor %}
  94 +
71 95 </div>
72 96  
73 97 {% endblock %}
... ...
phrase_expansions/views.py
  1 +from collections import defaultdict
  2 +
1 3 from django.shortcuts import render
2 4  
  5 +from django.utils.translation import gettext as _
  6 +
  7 +from phrase_expansions.models import PhraseExpansionType, PhraseExpansion
  8 +
  9 +def EXPANSION_OPINION():
  10 + return {
  11 + 'col' : _('potoczne'),
  12 + 'dat' : _('archaiczne'),
  13 + 'unc' : _('wątpliwe'),
  14 + 'cer' : _('pewne'),
  15 + }
  16 +
3 17 def phrase_expansions(request):
4   - return render(request, 'phrase_expansions.html', { })
  18 + expansions = defaultdict(list)
  19 + expansions = [
  20 + {
  21 + 'phrase_type' : phrase_type,
  22 + 'title' : '{} – {}'.format(phrase_type, title),
  23 + 'max_positions' : max(exp_type.max_positions for exp_type in PhraseExpansionType.objects.filter(phrase_type=phrase_type)),
  24 + 'phrase_subtypes' : [
  25 + {
  26 + 'phrase_subtype' : exp_type.phrase_subtype,
  27 + 'title' : '{}({})'.format(phrase_type, exp_type.phrase_subtype),
  28 + 'max_positions' : exp_type.max_positions,
  29 + 'expansions' : [
  30 + {
  31 + 'opinion_str' : EXPANSION_OPINION()[exp.opinion.key],
  32 + 'opinion_sym' : exp.opinion.key,
  33 + 'num_positions' : len(exp.positions.all()),
  34 + 'positions' : [
  35 + {
  36 + 'phrases' : [
  37 + {
  38 + 'str' : phr.text_rep,
  39 + 'desc' : phr.descriptions.get(lang=request.LANGUAGE_CODE).description,
  40 + } for phr in pos.phrases.all()
  41 + ]
  42 + } for pos in exp.positions.all()
  43 + ],
  44 + } for exp in exp_type.expansions.all()
  45 + ],
  46 + } for exp_type in PhraseExpansionType.objects.filter(phrase_type=phrase_type)
  47 + ],
  48 + } for phrase_type, title in (
  49 + ('advp', _('frazy przysłówkowe')),
  50 + ('xp', _('frazy okolicznikowe')),
  51 + ('comprepnp', _('frazy przyimkowe z przyimkiem złożonym')),
  52 + ('distrp', _('fraza dystrybutywna')),
  53 + ('possp', _('fraza posesywna')),
  54 + )
  55 + ]
  56 + return render(request, 'phrase_expansions.html', { 'expansions' : expansions })
... ...