fix generation of <question> tags
[librarian.git] / librarian / pyhtml.py
1 # -*- coding: utf-8 -*-
2 #
3 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
4 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
5 #
6 from lxml import etree
7 from librarian import OutputFile, RDFNS, DCNS
8 from xmlutils import Xmill, tag, tagged, ifoption
9  
10
11 class EduModule(Xmill):
12     def __init__(self, *args):
13         super(EduModule, self).__init__(*args)
14         self.activity_counter = 0
15
16     def handle_powiesc(self, element):
17         return u"""
18 <div class="module" id="book-text">
19  <span class="teacher-toggle">
20   <input type="checkbox" name="teacher-toggle" id="teacher-toggle"/>
21   <label for="teacher-toggle">Pokaż treść dla nauczyciela</label>
22  </span>
23
24 """, u"</div>"
25
26
27     handle_autor_utworu = tag("span", "author")
28     handle_nazwa_utworu = tag("h1", "title")
29     handle_dzielo_nadrzedne = tag("span", "collection")
30     handle_podtytul = tag("span", "subtitle")
31     handle_naglowek_akt = handle_naglowek_czesc = handle_srodtytul = tag("h2")
32     handle_naglowek_scena = handle_naglowek_rozdzial = tag('h3')
33     handle_naglowek_osoba = handle_naglowek_podrozdzial = tag('h4')
34     handle_akap = handle_akap_dialog = handle_akap_cd = tag('p', 'paragraph')
35     handle_strofa = tag('div', 'stanza')
36
37     def handle_aktywnosc(self, element):
38         self.activity_counter += 1
39         self.options = {
40             'activity': True, 
41             'activity_counter': self.activity_counter
42             }
43         submill = EduModule()
44
45         opis = submill.generate(element.xpath('opis')[0])
46
47         n = element.xpath('wskazowki')
48         if n: wskazowki = submill.generate(n[0])
49
50         else: wskazowki = ''
51         n = element.xpath('pomoce')
52
53         if n: pomoce = submill.generate(n[0])
54         else: pomoce = ''
55
56         forma = ''.join(element.xpath('forma/text()'))
57
58         czas = ''.join(element.xpath('czas/text()'))
59
60         counter = self.activity_counter
61
62         return u"""
63 <div class="activity">
64  <div class="text">%(counter)d. 
65   %(opis)s
66   %(wskazowki)s
67  </div>
68  <div class="info">
69   <p>Czas: %(czas)s min</p>
70   <p>Forma: %(forma)s</p>
71   %(pomoce)s
72  </div>
73  <div class="clearboth"></div>
74 </div>
75 """ % locals()
76
77     handle_opis = ifoption(activity=False)(tag('div', 'description'))
78     handle_wskazowki = ifoption(activity=False)(tag('div', ('hints', 'teacher')))
79     
80     @ifoption(activity=False)
81     @tagged('div', 'materials')
82     def handle_pomoce(self, _):
83         return "Pomoce: ", ""
84     
85     def handle_czas(self, *_):
86         return
87
88     def handle_forma(self, *_):
89         return
90             
91     def handle_cwiczenie(self, element):
92         excercise_handlers = {
93             'wybor': Wybor,
94             'uporzadkuj': Uporzadkuj,
95             'luki': Luki,
96             'zastap': Zastap,
97             'przyporzadkuj': Przyporzadkuj
98             }
99         
100         typ = element.attrib['typ']
101         handler = excercise_handlers[typ](self.options)
102         return handler.generate(element)
103
104     # Lists
105     def handle_lista(self, element, attrs={}):
106         ltype = element.attrib.get('typ', 'punkt')
107         if ltype == 'slowniczek':
108             self.options = {'slowniczek': True}
109             return '<div class="slowniczek">', '</div>'
110 ### robie teraz punkty wyboru
111         listtag = {'num': 'ol', 
112                'punkt': 'ul', 
113                'alfa': 'ul', 
114                'czytelnia': 'ul'}[ltype]
115
116         classes = attrs.get('class', '')
117         if classes: del attrs['class']
118             
119         attrs_s = ' '.join(['%s="%s"' % kv for kv in attrs.items()])
120         if attrs_s: attrs_s = ' ' + attrs_s
121             
122         return '<%s class="lista %s %s"%s>' % (listtag, ltype, classes, attrs_s), '</%s>' % listtag
123
124     def handle_punkt(self, element):
125         if self.options['slowniczek']:
126             return '<dl>', '</dl>'
127         else:
128             return '<li>', '</li>'
129
130     def handle_rdf__RDF(self, _):
131         # ustal w opcjach  rzeczy :D
132         return 
133
134
135 class Excercise(EduModule):
136     def __init__(self, *args, **kw):
137         self.question_counter = 0
138         super(Excercise, self).__init__(*args, **kw)
139
140     def handle_cwiczenie(self, element):
141         self.options = {'excercise': element.attrib['typ']}
142         self.question_counter = 0
143         self.piece_counter = 0
144
145         pre = u"""
146 <div class="excercise %(typ)s" data-type="%(typ)s">
147 <form action="#" method="POST">
148 """ % element.attrib
149         post = u"""
150 <div class="buttons">
151 <span class="message"></span>
152 <input type="button" class="check" value="sprawdź"/>
153 <input type="button" class="solutions" value="pokaż rozwiązanie"/>
154 </div>
155 </form>
156 </div>
157 """
158         # Add a single <pytanie> tag if it's not there
159         if not element.xpath(".//pytanie"):
160             qpre, qpost = self.handle_pytanie(element)
161             pre = pre + qpre
162             post = qpost + post
163         return pre, post
164  
165     def handle_pytanie(self, element):
166         """This will handle <cwiczenie> element, when there is no <pytanie>
167         """
168         self.question_counter += 1
169         self.piece_counter = 0
170         solution = element.attrib.get('rozw', None)
171         if solution: solution_s = ' data-solution="%s"' % solution
172         else: solution_s = ''
173
174         return '<div class="question" data-no="%d" %s>' %\
175             (self.question_counter, solution_s), \
176     "</div>"    
177
178
179 class Wybor(Excercise):
180     def handle_punkt(self, element):
181         if self.options['excercise'] and element.attrib.get('nazwa', None):
182             qc = self.question_counter
183             self.piece_counter += 1
184             no = self.piece_counter
185             eid = "q%(qc)d_%(no)d" % locals()
186             return u"""
187 <li class="question-piece" data-qc="%(qc)d" data-no="%(no)d">
188 <input type="checkbox" name="" id="%(eid)s" />
189 <label for="%(eid)s">
190 """ % locals(), u"</label></li>"
191
192         else:
193             return super(Wybor, self).handle_punkt(element)
194
195
196 class Uporzadkuj(Excercise):
197     def handle_pytanie(self, element):
198         """
199 Overrides the returned content default handle_pytanie
200         """
201         # we ignore the result, returning our own
202         super(Uporzadkuj, self).handle_pytanie(element)
203         order_items = element.xpath(".//punkt/@rozw")
204
205         return u"""<div class="question" data-original="%s" data-no="%s">""" % \
206             (','.join(order_items), self.question_counter), \
207             u"""</div>"""
208     
209     def handle_punkt(self, element):
210         return """<li class="question-piece" data-pos="%(rozw)s"/>""" \
211             % element.attrib,\
212             "</li>"
213
214
215 class Luki(Excercise):
216     def handle_luka(self, element):
217         return '<input type="text" class="luka question-piece" data-solution="%s"></input>' % element.text
218
219
220
221 class Zastap(Excercise):
222     def handle_zastap(self, element):
223         return '<span class="zastap question-piece" data-solution="%(rozw)s">' % element.attrib, '</span>'
224
225
226 class Przyporzadkuj(Excercise):
227     def handle_lista(self, lista):
228         print "in lista %s %s" % (lista.attrib, self.options)
229         if 'nazwa' in lista.attrib:
230             attrs = {
231                 'data-name': lista.attrib['nazwa'],
232                 'class': 'predicate'
233                 }
234             self.options = {'predicate': True}
235         elif 'cel' in lista.attrib:
236             attrs = {
237                 'data-target': lista.attrib['cel'],
238                 'class': 'subject'
239                 }
240             self.options = {'subject': True}
241         else:
242             attrs = {}
243         return super(Przyporzadkuj, self).handle_lista(lista, attrs)  
244
245
246     def handle_punkt(self, element):
247         print "in punkt %s %s" % (element.attrib, self.options)
248
249         if self.options['subject']:
250             return '<li data-solution="%(rozw)s" class="question-piece draggable multiple">' % element.attrib, '</li>'
251         elif self.options['predicate']:
252             return '<li data-predicate="%(nazwa)s">' % element.attrib, '<ul class="subjects droppable"><li>Placeholder</li></ul></li>'
253         else:
254             return super(Przyporzadkuj, self).handle_punkt(element)
255
256
257
258
259 def transform(wldoc, stylesheet='edumed', options=None, flags=None):
260     """Transforms the WL document to XHTML.
261
262     If output_filename is None, returns an XML,
263     otherwise returns True if file has been written,False if it hasn't.
264     File won't be written if it has no content.
265     """
266     
267     edumod = EduModule(options)
268 #    from pdb import set_trace; set_trace()
269     html = edumod.generate(wldoc.edoc.getroot())
270
271     return OutputFile.from_string(html.encode('utf-8'))