Przyporzadkuj -- minimum answers
[librarian.git] / librarian / pyhtml.py
index 5d4dc50..4ef04bc 100644 (file)
@@ -6,47 +6,27 @@
 from lxml import etree
 from librarian import OutputFile, RDFNS, DCNS
 from xmlutils import Xmill, tag, tagged, ifoption
 from lxml import etree
 from librarian import OutputFile, RDFNS, DCNS
 from xmlutils import Xmill, tag, tagged, ifoption
+from librarian import functions
+import re
+import random
+
 
 class EduModule(Xmill):
     def __init__(self, *args):
         super(EduModule, self).__init__(*args)
         self.activity_counter = 0
 
 class EduModule(Xmill):
     def __init__(self, *args):
         super(EduModule, self).__init__(*args)
         self.activity_counter = 0
-        self.question_counter = 0
-
-    def handle_utwor(self, element):
-        v = {}
-#        from pdb import *; set_trace()
-        v['title'] = element.xpath('//dc:title/text()', namespaces={'dc':DCNS.uri})[0]
-        return u"""
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8"/>
-<title>%(title)s</title>
-<link rel="stylesheet" type="text/css" href="master.book.css"/>
-<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
-<script src="edumed.js"></script>
-</head>
-<body>
-""" % v, u"""
-</body>
-</html>
-
-"""
+        self.register_text_filter(lambda t: functions.substitute_entities(None, t))
 
 
-    
     def handle_powiesc(self, element):
         return u"""
 <div class="module" id="book-text">
     def handle_powiesc(self, element):
         return u"""
 <div class="module" id="book-text">
- <span class="teacher-toggle">
+<!-- <span class="teacher-toggle">
   <input type="checkbox" name="teacher-toggle" id="teacher-toggle"/>
   <label for="teacher-toggle">Pokaż treść dla nauczyciela</label>
   <input type="checkbox" name="teacher-toggle" id="teacher-toggle"/>
   <label for="teacher-toggle">Pokaż treść dla nauczyciela</label>
- </span>
+ </span>-->
 
 """, u"</div>"
 
 
 """, u"</div>"
 
-
     handle_autor_utworu = tag("span", "author")
     handle_nazwa_utworu = tag("h1", "title")
     handle_dzielo_nadrzedne = tag("span", "collection")
     handle_autor_utworu = tag("span", "author")
     handle_nazwa_utworu = tag("h1", "title")
     handle_dzielo_nadrzedne = tag("span", "collection")
@@ -60,7 +40,7 @@ class EduModule(Xmill):
     def handle_aktywnosc(self, element):
         self.activity_counter += 1
         self.options = {
     def handle_aktywnosc(self, element):
         self.activity_counter += 1
         self.options = {
-            'activity': True, 
+            'activity': True,
             'activity_counter': self.activity_counter
             }
         submill = EduModule()
             'activity_counter': self.activity_counter
             }
         submill = EduModule()
@@ -84,7 +64,7 @@ class EduModule(Xmill):
 
         return u"""
 <div class="activity">
 
         return u"""
 <div class="activity">
- <div class="text">%(counter)d. 
+ <div class="text">%(counter)d.
   %(opis)s
   %(wskazowki)s
  </div>
   %(opis)s
   %(wskazowki)s
  </div>
@@ -99,80 +79,277 @@ class EduModule(Xmill):
 
     handle_opis = ifoption(activity=False)(tag('div', 'description'))
     handle_wskazowki = ifoption(activity=False)(tag('div', ('hints', 'teacher')))
 
     handle_opis = ifoption(activity=False)(tag('div', 'description'))
     handle_wskazowki = ifoption(activity=False)(tag('div', ('hints', 'teacher')))
-    
+
     @ifoption(activity=False)
     @tagged('div', 'materials')
     def handle_pomoce(self, _):
         return "Pomoce: ", ""
     @ifoption(activity=False)
     @tagged('div', 'materials')
     def handle_pomoce(self, _):
         return "Pomoce: ", ""
-    
+
     def handle_czas(self, *_):
         return
 
     def handle_forma(self, *_):
         return
     def handle_czas(self, *_):
         return
 
     def handle_forma(self, *_):
         return
-        
+
+    def handle_cwiczenie(self, element):
+        excercise_handlers = {
+            'wybor': Wybor,
+            'uporzadkuj': Uporzadkuj,
+            'luki': Luki,
+            'zastap': Zastap,
+            'przyporzadkuj': Przyporzadkuj,
+            'prawdafalsz': PrawdaFalsz
+            }
+
+        typ = element.attrib['typ']
+        handler = excercise_handlers[typ](self.options)
+        return handler.generate(element)
+
+    # Lists
+    def handle_lista(self, element, attrs={}):
+        ltype = element.attrib.get('typ', 'punkt')
+        if ltype == 'slowniczek':
+            self.options = {'slowniczek': True}
+            return '<div class="slowniczek">', '</div>'
+### robie teraz punkty wyboru
+        listtag = {'num': 'ol',
+               'punkt': 'ul',
+               'alfa': 'ul',
+               'czytelnia': 'ul'}[ltype]
+
+        classes = attrs.get('class', '')
+        if classes: del attrs['class']
+
+        attrs_s = ' '.join(['%s="%s"' % kv for kv in attrs.items()])
+        if attrs_s: attrs_s = ' ' + attrs_s
+
+        return '<%s class="lista %s %s"%s>' % (listtag, ltype, classes, attrs_s), '</%s>' % listtag
+
+    def handle_punkt(self, element):
+        if self.options['slowniczek']:
+            return '<dl>', '</dl>'
+        else:
+            return '<li>', '</li>'
+
+    def handle_rdf__RDF(self, _):
+        # ustal w opcjach  rzeczy :D
+        return
+
+
+class Excercise(EduModule):
+    def __init__(self, *args, **kw):
+        self.question_counter = 0
+        super(Excercise, self).__init__(*args, **kw)
+
+    def handle_rozw_kom(self, element):
+        return None
+
     def handle_cwiczenie(self, element):
         self.options = {'excercise': element.attrib['typ']}
         self.question_counter = 0
         self.piece_counter = 0
 
     def handle_cwiczenie(self, element):
         self.options = {'excercise': element.attrib['typ']}
         self.question_counter = 0
         self.piece_counter = 0
 
-        return u"""
+        pre = u"""
 <div class="excercise %(typ)s" data-type="%(typ)s">
 <form action="#" method="POST">
 <div class="excercise %(typ)s" data-type="%(typ)s">
 <form action="#" method="POST">
-""" % element.attrib, \
-u"""
+""" % element.attrib
+        post = u"""
 <div class="buttons">
 <span class="message"></span>
 <input type="button" class="check" value="sprawdź"/>
 <input type="button" class="solutions" value="pokaż rozwiązanie"/>
 <div class="buttons">
 <span class="message"></span>
 <input type="button" class="check" value="sprawdź"/>
 <input type="button" class="solutions" value="pokaż rozwiązanie"/>
+<input type="button" class="reset" value="reset"/>
 </div>
 </form>
 </div>
 """
 </div>
 </form>
 </div>
 """
+        # Add a single <pytanie> tag if it's not there
+        if not element.xpath(".//pytanie"):
+            qpre, qpost = self.handle_pytanie(element)
+            pre = pre + qpre
+            post = qpost + post
+        return pre, post
+
     def handle_pytanie(self, element):
     def handle_pytanie(self, element):
+        """This will handle <cwiczenie> element, when there is no <pytanie>
+        """
+        add_class = ""
         self.question_counter += 1
         self.piece_counter = 0
         solution = element.attrib.get('rozw', None)
         if solution: solution_s = ' data-solution="%s"' % solution
         else: solution_s = ''
 
         self.question_counter += 1
         self.piece_counter = 0
         solution = element.attrib.get('rozw', None)
         if solution: solution_s = ' data-solution="%s"' % solution
         else: solution_s = ''
 
-        return '<div class="question" data-no="%d" %s>' %\
-            (self.question_counter, solution_s), \
-    "</div>"    
+        handles = element.attrib.get('uchwyty', None)
+        if handles:
+            add_class += ' handles handles-%s' % handles
+            self.options = {'handles': handles}
 
 
-    # Lists
-    def handle_lista(self, element):
-        ltype = element.attrib.get('typ', 'punkt')
-        if ltype == 'slowniczek':
-            self.options = {'slowniczek': True}
-            return '<div class="slowniczek">', '</div>'
-### robie teraz punkty wyboru
-        listtag = {'num': 'ol', 
-               'punkt': 'ul', 
-               'alfa': 'ul', 
-               'czytelnia': 'ul'}[ltype]
+        minimum = element.attrib.get('min', None)
+        if minimum: minimum_s = ' data-minimum="%d"' % int(minimum)
+        else: minimum_s = ''
 
 
-        return '<%s class="lista %s">' % (listtag, ltype), '</%s>' % listtag
+        return '<div class="question%s" data-no="%d" %s>' %\
+            (add_class, self.question_counter, solution_s + minimum_s), \
+            "</div>"
+
+
+class Wybor(Excercise):
+    def handle_cwiczenie(self, element):
+        pre, post = super(Wybor, self).handle_cwiczenie(element)
+        is_single_choice = True
+        for p in element.xpath(".//pytanie"):
+            solutions = re.split(r"[, ]+", p.attrib['rozw'])
+            if len(solutions) != 1:
+                is_single_choice = False
+                break
+        self.options = {'single': is_single_choice}
+        return pre, post
 
     def handle_punkt(self, element):
 
     def handle_punkt(self, element):
-        if self.options['excercise'] and element.attrib['nazwa']:
+        if self.options['excercise'] and element.attrib.get('nazwa', None):
             qc = self.question_counter
             self.piece_counter += 1
             no = self.piece_counter
             qc = self.question_counter
             self.piece_counter += 1
             no = self.piece_counter
+            eid = "q%(qc)d_%(no)d" % locals()
+            aname = element.attrib.get('nazwa', None)
+            if self.options['single']:
+                return u"""
+<li class="question-piece" data-qc="%(qc)d" data-no="%(no)d" data-name="%(aname)s">
+<input type="radio" name="q%(qc)d" id="%(eid)s" value="%(aname)s" />
+<label for="%(eid)s">
+                """ % locals(), u"</label></li>"
+            else:
+                return u"""
+<li class="question-piece" data-qc="%(qc)d" data-no="%(no)d" data-name="%(aname)s">
+<input type="checkbox" name="%(eid)s" id="%(eid)s" />
+<label for="%(eid)s">
+""" % locals(), u"</label></li>"
 
 
-            return u"""
-<li class="question-piece" data-qc="%(qc)d" data-no="%(no)d"><input type="checkbox" name="q%(qc)d_%(no)d"/>
-""" % locals(), u"</li>"
+        else:
+            return super(Wybor, self).handle_punkt(element)
 
 
-        elif self.options['slowniczek']:
-            return '<dl>', '</dl>'
+
+class Uporzadkuj(Excercise):
+    def handle_pytanie(self, element):
+        """
+Overrides the returned content default handle_pytanie
+        """
+        # we ignore the result, returning our own
+        super(Uporzadkuj, self).handle_pytanie(element)
+        order_items = element.xpath(".//punkt/@rozw")
+
+        return u"""<div class="question" data-original="%s" data-no="%s">""" % \
+            (','.join(order_items), self.question_counter), \
+            u"""</div>"""
+
+    def handle_punkt(self, element):
+        return """<li class="question-piece" data-pos="%(rozw)s"/>""" \
+            % element.attrib,\
+            "</li>"
+
+
+class Luki(Excercise):
+    def find_pieces(self, question):
+        return question.xpath("//luka")
+
+    def solution_html(self, piece):
+        return piece.text + ''.join(
+            [etree.tostring(n, encoding=unicode)
+             for n in piece])
+
+    def handle_pytanie(self, element):
+        qpre, qpost = super(Luki, self).handle_pytanie(element)
+
+        luki = list(enumerate(self.find_pieces(element)))
+        luki_html = ""
+        i = 0
+        random.shuffle(luki)
+        for (i, luka) in luki:
+            i += 1
+            luka_html = self.solution_html(luka)
+            luki_html += u'<span class="draggable question-piece" data-no="%d">%s</span>' % (i, luka_html)
+        self.words_html = '<div class="words">%s</div>' % luki_html
+
+        return qpre, qpost
+
+    def handle_opis(self, element):
+        pre, post = super(Luki, self).handle_opis(element)
+        return pre, self.words_html + post
+
+    def handle_luka(self, element):
+        self.piece_counter += 1
+        return '<span class="placeholder" data-solution="%d"></span>' % self.piece_counter
+
+
+class Zastap(Luki):
+    def find_pieces(self, question):
+        return question.xpath("//zastap")
+
+    def solution_html(self, piece):
+        return piece.attrib['rozw']
+
+    def handle_zastap(self, element):
+        self.piece_counter += 1
+        return '<span class="placeholder zastap question-piece" data-solution="%d">' \
+            % self.piece_counter, '</span>'
+
+
+class Przyporzadkuj(Excercise):
+    def handle_pytanie(self, element):
+        pre, post = super(Przyporzadkuj, self).handle_pytanie(element)
+        minimum = element.attrib.get("min", None)
+        if minimum:
+            self.options = {"min": int(minimum)}
+        return pre, post
+
+    def handle_lista(self, lista):
+        if 'nazwa' in lista.attrib:
+            attrs = {
+                'data-name': lista.attrib['nazwa'],
+                'class': 'predicate'
+            }
+            self.options = {'predicate': True}
+        elif 'cel' in lista.attrib:
+            attrs = {
+                'data-target': lista.attrib['cel'],
+                'class': 'subject'
+            }
+            self.options = {'subject': True, 'handles': 'uchwyty' in lista.attrib}
         else:
         else:
-            return '<li>', '</li>'
+            attrs = {}
+        pre, post = super(Przyporzadkuj, self).handle_lista(lista, attrs)
+        return pre, post + '<br class="clr"/>'
 
 
-    def handle_rdf__RDF(self, _):
-        # ustal w opcjach  rzeczy :D
-        return 
+    def handle_punkt(self, element):
+        if self.options['subject']:
+            self.piece_counter += 1
+            if self.options['handles']:
+                return '<li><span data-solution="%s" data-no="%s" class="question-piece draggable handle">%s</span>' % (element.attrib['rozw'], self.piece_counter, self.piece_counter), '</li>'
+            else:
+                return '<li data-solution="%s" data-no="%s" class="question-piece draggable">' % (element.attrib['rozw'], self.piece_counter), '</li>'
+
+        elif self.options['predicate']:
+            if self.options['min']:
+                placeholders = u'<li class="placeholder"/>' * self.options['min']
+            else:
+                placeholders = u'<li class="placeholder multiple"/>'
+            return '<li data-predicate="%(nazwa)s">' % element.attrib, '<ul class="subjects">' + placeholders + '</ul></li>'
+
+        else:
+            return super(Przyporzadkuj, self).handle_punkt(element)
+
+
+class PrawdaFalsz(Excercise):
+    def handle_punkt(self, element):
+        if 'rozw' in element.attrib:
+            return u'''<li data-solution="%s" class="question-piece">
+            <span class="buttons">
+            <a href="#" data-value="true" class="true">Prawda</a>
+            <a href="#" data-value="false" class="false">Fałsz</a>
+        </span>''' % {'prawda': 'true', 'falsz': 'false'}[element.attrib['rozw']], '</li>'
+        else:
+            return super(PrawdaFalsz, self).handle_punkt(element)
 
 
 def transform(wldoc, stylesheet='edumed', options=None, flags=None):
 
 
 def transform(wldoc, stylesheet='edumed', options=None, flags=None):
@@ -182,7 +359,6 @@ def transform(wldoc, stylesheet='edumed', options=None, flags=None):
     otherwise returns True if file has been written,False if it hasn't.
     File won't be written if it has no content.
     """
     otherwise returns True if file has been written,False if it hasn't.
     File won't be written if it has no content.
     """
-    
     edumod = EduModule(options)
 #    from pdb import set_trace; set_trace()
     html = edumod.generate(wldoc.edoc.getroot())
     edumod = EduModule(options)
 #    from pdb import set_trace; set_trace()
     html = edumod.generate(wldoc.edoc.getroot())