Weryfikacja podczas zapisu XML i DC. TODO: DC jeszcze nie działa tak jak powinno.
authorŁukasz Rekucki <lrekucki@gmail.com>
Wed, 2 Sep 2009 06:45:52 +0000 (08:45 +0200)
committerŁukasz Rekucki <lrekucki@gmail.com>
Wed, 2 Sep 2009 06:45:52 +0000 (08:45 +0200)
apps/explorer/forms.py
apps/explorer/views.py
project/static/css/master.css
project/static/js/editor.js
project/templates/explorer/editor.html

index af1534e..d79bc74 100644 (file)
@@ -2,10 +2,45 @@ from django import forms
 
 from lxml import etree
 from librarian import dcparser
-
+import django.utils
 
 from explorer import models
 
+class PersonField(forms.CharField):
+    def clean(self, value):
+        try:
+            return dcparser.Person.from_text( super(PersonField, self).clean(value) )
+        except ValueError, e:
+            raise django.utils.ValidationError(e.message)        
+
+class PersonListField(forms.Field):
+
+    def __init__(self, *args, **kwargs):
+        super(PersonListField, self).__init__(*args, **kwargs)
+    
+    def _get_initial(self):
+        return u'\n'.join( ( unicode(person) for person in self._initial) )
+
+    def _set_initial(self, value):
+        if value is None:
+            self._initial = None
+        elif isinstance(value, list):
+            self._initial = [ e if isinstance(e, dcparser.Person) \
+                else dcparser.Person.from_text(e) for e in value ]
+        elif isinstance(value, basestring):
+            self._initial = [dcparser.Person.from_text(token) for token in value.split('\n') ]
+        else:
+            raise ValueError("Invalid value. Must be a list of dcparser.Person or string")    
+
+    initial = property(_get_initial, _set_initial)
+
+    def clean(self, value):
+        super(PersonListField, self).clean(value)
+        people = value.split('\n')
+        try:
+            return [dcparser.Person.from_text(person) for person in people]
+        except ValueError, e:
+            raise django.utils.ValidationError(e.message)        
 
 class BookForm(forms.Form):
     content = forms.CharField(widget=forms.Textarea)
@@ -23,17 +58,18 @@ class ImageFoldersForm(forms.Form):
 
 
 class DublinCoreForm(forms.Form):
-    wiki_url = forms.URLField(verify_exists=False)
-    author = forms.CharField()
+    about = forms.URLField(verify_exists=False)
+    author = PersonField()
     title = forms.CharField()
     epoch = forms.CharField()
     kind = forms.CharField()
     genre = forms.CharField()
     created_at = forms.DateField()
     released_to_public_domain_at = forms.DateField()
-    translator = forms.CharField(required=False)
-    technical_editor = forms.CharField(required=False)
-    publisher = forms.CharField()
+    editors = PersonListField(widget=forms.Textarea, required=False)
+    translator = PersonField(required=False)
+    technical_editor = PersonField(required=False)
+    publisher = PersonField()
     source_name = forms.CharField(widget=forms.Textarea)
     source_url = forms.URLField(verify_exists=False)
     url = forms.URLField(verify_exists=False)
@@ -41,16 +77,14 @@ class DublinCoreForm(forms.Form):
     license = forms.CharField(required=False)
     license_description = forms.CharField(widget=forms.Textarea, required=False)
     
-    commit_message = forms.CharField(required=False)
+    commit_message = forms.CharField(required=False, widget=forms.HiddenInput)
     
     def __init__(self, *args, **kwargs):
         text = None
-        if 'text' in kwargs:
-            text = kwargs.pop('text')
+        info = kwargs.pop('info', None)
         
         super(DublinCoreForm, self).__init__(*args, **kwargs)
         
-        if text is not None:
-            book_info = dcparser.BookInfo.from_string(text)
-            for name, value in book_info.to_dict().items():
-                self.fields[name].initial = value
\ No newline at end of file
+        if isinstance(info, dcparser.BookInfo):
+            for name, value in info.to_dict().items():
+                self.fields[name].initial = value
index 585edcc..d4d0f6d 100644 (file)
@@ -1,9 +1,11 @@
+# -*- coding: utf-8 -*-
 from librarian import html
 import hg, urllib2, time
 
 from django.utils import simplejson as json
-from lxml import etree
-from librarian import dcparser
+
+from librarian import dcparser, parser
+from librarian import ParseError, ValidationError
 
 from django.views.generic.simple import direct_to_template
 
@@ -87,21 +89,28 @@ def file_upload(request, repo):
 @with_repo
 def file_xml(request, repo, path):
     if request.method == 'POST':
+        errors = None
         form = forms.BookForm(request.POST)
         if form.is_valid():
             print 'Saving whole text.', request.user.username
             def save_action():
                 print 'In branch: ' + repo.repo[None].branch()
                 repo._add_file(path, form.cleaned_data['content'])                
-                repo._commit(message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'), user=request.user.username)
+                repo._commit(message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'),\
+                     user=request.user.username)
+            try:
+                # wczytaj dokument z ciągu znaków -> weryfikacja
+                document = parser.WLDocument.from_string(form.cleaned_data['content'])
+
+                #  save to user's branch
+                repo.in_branch(save_action, models.user_branch(request.user) );
+            except (ParseError, ValidationError), e:
+                errors = [e.message]              
 
-            print repo.in_branch(save_action, models.user_branch(request.user) );
-            result = "ok"
-        else:
-            result = "error"
+        if not errors:
+            errors = dict( (field[0], field[1].as_text()) for field in form.errors.iteritems() )
 
-        errors = dict( (field[0], field[1].as_text()) for field in form.errors.iteritems() )
-        return HttpResponse( json.dumps({'result': result, 'errors': errors}) );
+        return HttpResponse(json.dumps({'result': errors and 'error' or 'ok', 'errors': errors}));
 
     form = forms.BookForm()
     data = repo.get_file(path, models.user_branch(request.user))
@@ -113,32 +122,46 @@ def file_xml(request, repo, path):
 def file_dc(request, path, repo):
     if request.method == 'POST':
         form = forms.DublinCoreForm(request.POST)
+        errors = None
         
         if form.is_valid():
             def save_action():
                 file_contents = repo._get_file(path)
-                doc = etree.fromstring(file_contents)
 
-                book_info = dcparser.BookInfo()
-                for name, value in form.cleaned_data.items():
-                    if value is not None and value != '':
-                        setattr(book_info, name, value)
-                rdf = etree.XML(book_info.to_xml())
+                # wczytaj dokument z repozytorium
+                document = parser.WLDocument.from_string(file_contents)
+
+                rdf_ns = dcparser.BookInfo.RDF
+                dc_ns = dcparser.BookInfo.DC
+
+                rdf_attrs = {rdf_ns('about'): form.cleaned_data.pop('about')}
+                field_dict = {}
+                    
+                for key, value in form.cleaned_data.items():
+                    field_dict[ dc_ns(key) ] = value if isinstance(value, list) else [value]
 
-                old_rdf = doc.getroottree().find('//{http://www.w3.org/1999/02/22-rdf-syntax-ns#}RDF')
-                old_rdf.getparent().remove(old_rdf)
-                doc.insert(0, rdf)
-                repo._add_file(path, etree.tostring(doc, pretty_print=True, encoding=unicode))
-                repo._commit(message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'), user=request.user.username)
+                print field_dict
 
-            repo.in_branch(save_action, models.user_branch(request.user) )
+                new_info = dcparser.BookInfo(rdf_attrs, field_dict)
+                document.book_info = new_info
 
-            result = "ok"
-        else:
-            result = "error" 
+                print "SAVING DC"
 
-        errors = dict( (field[0], field[1].as_text()) for field in form.errors.iteritems() )
-        return HttpResponse( json.dumps({'result': result, 'errors': errors}) );
+                    # zapisz
+                repo._add_file(path, document.serialize())
+                repo._commit( \
+                    message=(form.cleaned_data['commit_message'] or 'Lokalny zapis platformy.'), \
+                    user=request.user.username )
+                
+            try:
+                repo.in_branch(save_action, models.user_branch(request.user) )
+            except (ParseError, ValidationError), e:
+                errors = [e.message]
+
+        if errors is None:
+            errors = dict( (field[0], field[1].as_text()) for field in form.errors.iteritems() )
+
+        return HttpResponse( json.dumps({'result': errors and 'error' or 'ok', 'errors': errors}) );
     
     fulltext = repo.get_file(path, models.user_branch(request.user))
     form = forms.DublinCoreForm(text=fulltext)       
@@ -189,8 +212,10 @@ def htmleditor_panel(request, path, repo):
 @with_repo
 def dceditor_panel(request, path, repo):
     user_branch = models.user_branch(request.user)
-    text = repo.get_file(path, user_branch)
-    form = forms.DublinCoreForm(text=text)       
+    doc_text = repo.get_file(path, user_branch)
+
+    document = parser.WLDocument.from_string(doc_text)
+    form = forms.DublinCoreForm(info=document.book_info)       
 
     return direct_to_template(request, 'explorer/panels/dceditor.html', extra_context={
         'fpath': path,
index 040549e..841467e 100644 (file)
@@ -353,12 +353,13 @@ div.isection p {
 #message-box {
     position: fixed;
     top: 2px;
-    left: 40%;   
+    left: 35%;
+    width: 33%;  
 }
 
 .msg-error, .msg-success, .msg-warning {
     overflow: hidden;
-    padding: 0.1em 0.2em;
+    padding: 0.1em 0.5em;
     text-align: center;
     border: 1px solid;
     -moz-border-radius: 8px;
@@ -367,13 +368,15 @@ div.isection p {
     line-height: 11pt;
     display: none;
 
-    width: 200px;
+    width: 100%;
 }
 
 
 .msg-error {
     background-color: red;
     border-color: red;
+    color: white;
+    font-weight: bold;
 }
 
 .msg-success {
@@ -416,4 +419,4 @@ div.isection p {
      position: relative;
      text-align: center;
      background-color: #CCC;
- }
\ No newline at end of file
+ }
index 6e63eb0..0a56c5a 100644 (file)
@@ -121,7 +121,7 @@ Editor.prototype.setupUI = function() {
        $('#panels > *.panel-wrap').each(function() {
                var panelWrap = $(this);
                $.log('wrap: ', panelWrap);
-               panel = new Panel(panelWrap);
+               var panel = new Panel(panelWrap);
                panelWrap.data('ctrl', panel); // attach controllers to wraps
         panel.load($('.panel-toolbar select', panelWrap).val());
         
@@ -130,6 +130,9 @@ Editor.prototype.setupUI = function() {
             panelWrap.data('ctrl').load(url);
             self.savePanelOptions();
         });
+
+        $('.panel-toolbar button.refresh-button', panelWrap).click(
+            function() { panel.refresh(); } );            
     });
 
        $(document).bind('panel:contentChanged', function() { self.onContentChanged.apply(self, arguments) });
@@ -220,20 +223,21 @@ Editor.prototype.saveToBranch = function(msg)
        }
 
        saveInfo = changed_panel.data('ctrl').saveInfo();
-        var postData = ''
-        if(saveInfo.postData instanceof Object)
-            postData = $.param(saveInfo.postData);
-        else
-            postData = saveInfo.postData;
+    var postData = ''
+    
+    if(saveInfo.postData instanceof Object)
+        postData = $.param(saveInfo.postData);
+    else
+        postData = saveInfo.postData;
 
-        postData += '&' + $.param({'commit_message': msg})
+    postData += '&' + $.param({'commit_message': msg})
 
        $.ajax({
                url: saveInfo.url,
                dataType: 'json',
                success: function(data, textStatus) {
                        if (data.result != 'ok')
-                               $.log('save errors: ', data.errors)
+                               self.showPopup('save-error', data.errors[0]);
                        else {
                                self.refreshPanels(changed_panel);
                 $('#toolbar-button-save').attr('disabled', 'disabled');
@@ -307,30 +311,37 @@ Editor.prototype.sendPullRequest = function () {
        }); */
 }
 
-Editor.prototype.showPopup = function(name) 
+Editor.prototype.showPopup = function(name, text
 {
     var self = this;
-    self.popupQueue.push(name)
+    self.popupQueue.push( [name, text] )
 
     if( self.popupQueue.length > 1) 
         return;
 
-    $('#message-box > #' + name).fadeIn();
+    var box = $('#message-box > #' + name);
+    $('span.data', box).html(text);
+    box.fadeIn();
  
-   self._nextPopup = function() {
+    self._nextPopup = function() {
         var elem = self.popupQueue.pop()
         if(elem) {
-            elem = $('#message-box > #' + elem);
-            elem.fadeOut(300, function() {
-                if( self.popupQueue.length > 0) 
-                    $('#message-box > #' + self.popupQueue[0]).fadeIn();
-                    setTimeout(self._nextPopup, 1700);
-            });
+            var box = $('#message-box > #' + elem[0]);
 
+            box.fadeOut(300, function() {
+                $('span.data', box).html();
+    
+                if( self.popupQueue.length > 0) {
+                    box = $('#message-box > #' + self.popupQueue[0][0]);
+                    $('span.data', box).html(self.popupQueue[0][1]);
+                    box.fadeIn();
+                    setTimeout(self._nextPopup, 5000);
+                }
+            });
         }
     }
 
-    setTimeout(self._nextPopup, 2000);
+    setTimeout(self._nextPopup, 5000);
 }
 
 
index 75e62c9..ae4be00 100644 (file)
@@ -19,9 +19,9 @@
 {% endblock %}
 
 {% block message-box %}
-    <div class="msg-success" id="save-successful">Zapisano :)</div>
-    <div class="msg-error" id="save-error">Błąd przy zapisie. <span class="errors" /></div>
-    <div class="msg-warning" id="not-implemented">Tej funkcji jeszcze nie ma :(</div>
+    <div class="msg-success" id="save-successful">Zapisano :)<span class="data" /></div>
+    <div class="msg-error" id="save-error">Błąd przy zapisie. <span class="data" /></div>
+    <div class="msg-warning" id="not-implemented">Tej funkcji jeszcze nie ma :(<span class="data" /></div>
 {% endblock %}
 
 {% block maincontent %}
@@ -36,6 +36,7 @@
                         <option value="{% url gallery_panel hash %}" name="gallery">Galeria skanów</option>
                         <option value="{% url dceditor_panel hash %}" name="dceditor">Edytor DublinCore</option>
                     </select>
+                    <button type="button" class="refresh-button">Odśwież</button>
                     <strong class="change-notification" style="display: none">Widok nieaktualny!</strong>
                </div>
                <div id="panel-{{n}}-content" class="panel-content"></div>