2cbc678f5a2bdc1075dc9b8839525a6e8c258ca3
[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 import random 
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             'prawdafalsz': PrawdaFalsz
99             }
100         
101         typ = element.attrib['typ']
102         handler = excercise_handlers[typ](self.options)
103         return handler.generate(element)
104
105     # Lists
106     def handle_lista(self, element, attrs={}):
107         ltype = element.attrib.get('typ', 'punkt')
108         if ltype == 'slowniczek':
109             self.options = {'slowniczek': True}
110             return '<div class="slowniczek">', '</div>'
111 ### robie teraz punkty wyboru
112         listtag = {'num': 'ol', 
113                'punkt': 'ul', 
114                'alfa': 'ul', 
115                'czytelnia': 'ul'}[ltype]
116
117         classes = attrs.get('class', '')
118         if classes: del attrs['class']
119             
120         attrs_s = ' '.join(['%s="%s"' % kv for kv in attrs.items()])
121         if attrs_s: attrs_s = ' ' + attrs_s
122             
123         return '<%s class="lista %s %s"%s>' % (listtag, ltype, classes, attrs_s), '</%s>' % listtag
124
125     def handle_punkt(self, element):
126         if self.options['slowniczek']:
127             return '<dl>', '</dl>'
128         else:
129             return '<li>', '</li>'
130
131     def handle_rdf__RDF(self, _):
132         # ustal w opcjach  rzeczy :D
133         return 
134
135
136 class Excercise(EduModule):
137     def __init__(self, *args, **kw):
138         self.question_counter = 0
139         super(Excercise, self).__init__(*args, **kw)
140
141     def handle_rozw_kom(self, element):
142         return None
143
144     def handle_cwiczenie(self, element):
145         self.options = {'excercise': element.attrib['typ']}
146         self.question_counter = 0
147         self.piece_counter = 0
148
149         pre = u"""
150 <div class="excercise %(typ)s" data-type="%(typ)s">
151 <form action="#" method="POST">
152 """ % element.attrib
153         post = u"""
154 <div class="buttons">
155 <span class="message"></span>
156 <input type="button" class="check" value="sprawdź"/>
157 <input type="button" class="solutions" value="pokaż rozwiązanie"/>
158 </div>
159 </form>
160 </div>
161 """
162         # Add a single <pytanie> tag if it's not there
163         if not element.xpath(".//pytanie"):
164             qpre, qpost = self.handle_pytanie(element)
165             pre = pre + qpre
166             post = qpost + post
167         return pre, post
168  
169     def handle_pytanie(self, element):
170         """This will handle <cwiczenie> element, when there is no <pytanie>
171         """
172         self.question_counter += 1
173         self.piece_counter = 0
174         solution = element.attrib.get('rozw', None)
175         if solution: solution_s = ' data-solution="%s"' % solution
176         else: solution_s = ''
177
178         return '<div class="question" data-no="%d" %s>' %\
179             (self.question_counter, solution_s), \
180     "</div>"
181
182
183 class Wybor(Excercise):
184     def handle_punkt(self, element):
185         if self.options['excercise'] and element.attrib.get('nazwa', None):
186             qc = self.question_counter
187             self.piece_counter += 1
188             no = self.piece_counter
189             eid = "q%(qc)d_%(no)d" % locals()
190             aname = element.attrib.get('nazwa', None)
191             return u"""
192 <li class="question-piece" data-qc="%(qc)d" data-no="%(no)d" data-name="%(aname)s">
193 <input type="checkbox" name="" id="%(eid)s" />
194 <label for="%(eid)s">
195 """ % locals(), u"</label></li>"
196
197         else:
198             return super(Wybor, self).handle_punkt(element)
199
200
201 class Uporzadkuj(Excercise):
202     def handle_pytanie(self, element):
203         """
204 Overrides the returned content default handle_pytanie
205         """
206         # we ignore the result, returning our own
207         super(Uporzadkuj, self).handle_pytanie(element)
208         order_items = element.xpath(".//punkt/@rozw")
209
210         return u"""<div class="question" data-original="%s" data-no="%s">""" % \
211             (','.join(order_items), self.question_counter), \
212             u"""</div>"""
213
214     def handle_punkt(self, element):
215         return """<li class="question-piece" data-pos="%(rozw)s"/>""" \
216             % element.attrib,\
217             "</li>"
218
219
220 class Luki(Excercise):
221     def handle_pytanie(self, element):
222         qpre, qpost = super(Luki, self).handle_pytanie(element)
223
224         luki = list(enumerate(element.xpath("//luka")))
225         luki_html = ""
226         i = 0
227         random.shuffle(luki)
228         for (i, luka) in luki:
229             i += 1
230             luka_html = luka.text + \
231                 ''.join([etree.tostring(n, encoding=unicode) for n in luka])
232             luki_html += u'<span class="draggable question-piece" data-no="%d">%s</span>' % (i, luka_html)
233         self.words_html = '<div class="words">%s</div>' % luki_html
234         
235         return qpre, qpost
236
237     def handle_opis(self, element):
238         pre, post = super(Luki, self).handle_opis(element)
239         return pre, self.words_html + post
240                 
241     def handle_luka(self, element):
242         self.piece_counter += 1
243         return '<span class="placeholder" data-solution="%d"></span>' % self.piece_counter
244
245
246 class Zastap(Excercise):
247     def handle_zastap(self, element):
248         return '<span class="zastap question-piece" data-solution="%(rozw)s">' % element.attrib, '</span>'
249
250
251 class Przyporzadkuj(Excercise):
252     def handle_lista(self, lista):
253         print "in lista %s %s" % (lista.attrib, self.options)
254         if 'nazwa' in lista.attrib:
255             attrs = {
256                 'data-name': lista.attrib['nazwa'],
257                 'class': 'predicate'
258                 }
259             self.options = {'predicate': True}
260         elif 'cel' in lista.attrib:
261             attrs = {
262                 'data-target': lista.attrib['cel'],
263                 'class': 'subject'
264                 }
265             self.options = {'subject': True}
266         else:
267             attrs = {}
268         pre, post = super(Przyporzadkuj, self).handle_lista(lista, attrs)
269         return pre, post + '<br class="clr"/>'
270
271     def handle_punkt(self, element):
272         self.piece_counter += 1
273         print "in punkt %s %s" % (element.attrib, self.options)
274
275         if self.options['subject']:
276             return '<li data-solution="%s" data-no="%s" class="question-piece draggable">' % (element.attrib['rozw'], self.piece_counter), '</li>'
277         
278         elif self.options['predicate']:
279             print etree.tostring(element, encoding=unicode)
280             placeholders = u'<li class="placeholder multiple"/>'
281             return '<li data-predicate="%(nazwa)s">' % element.attrib, '<ul class="subjects">' + placeholders + '</ul></li>'
282         
283         else:
284             return super(Przyporzadkuj, self).handle_punkt(element)
285
286
287 class PrawdaFalsz(Excercise):
288     def handle_punkt(self, element):
289         if 'rozw' in element.attrib:
290             return u'''<li data-solution="%s" class="question-piece">
291             <span class="buttons">
292             <a href="#" data-value="true" class="true">Prawda</a>
293             <a href="#" data-value="false" class="false">Fałsz</a>
294         </span>''' % {'prawda': 'true', 'falsz': 'false'}[element.attrib['rozw']], '</li>'
295         else:
296             return super(PrawdaFalsz, self).handle_punkt(element)
297
298
299 def transform(wldoc, stylesheet='edumed', options=None, flags=None):
300     """Transforms the WL document to XHTML.
301
302     If output_filename is None, returns an XML,
303     otherwise returns True if file has been written,False if it hasn't.
304     File won't be written if it has no content.
305     """
306     edumod = EduModule(options)
307 #    from pdb import set_trace; set_trace()
308     html = edumod.generate(wldoc.edoc.getroot())
309
310     return OutputFile.from_string(html.encode('utf-8'))