Edytor HTML znow powinien dzialac.
authorLukasz <lreqc@debian.(none)>
Mon, 26 Oct 2009 09:37:26 +0000 (05:37 -0400)
committerLukasz <lreqc@debian.(none)>
Mon, 26 Oct 2009 09:37:26 +0000 (05:37 -0400)
apps/api/handlers/library_handlers.py
apps/api/handlers/text_handler.py [changed mode: 0644->0755]
lib/wlrepo/mercurial_backend/document.py
lib/wlrepo/mercurial_backend/library.py
platforma/static/css/html.css
platforma/static/css/master.css [changed mode: 0644->0755]
platforma/static/js/models.js
platforma/static/js/views/html.js
platforma/templates/explorer/editor.html [changed mode: 0644->0755]

index 0a45a0b..8f8f2bc 100755 (executable)
@@ -231,7 +231,7 @@ class DocumentHandler(BaseHandler):
     @hglibrary
     def read(self, request, form, docid, lib):
         """Read document's meta data"""       
     @hglibrary
     def read(self, request, form, docid, lib):
         """Read document's meta data"""       
-        log.info(u"User '%s' wants to %s(%s) as %s" % \
+        log.info(u"User '%s' wants to edit %s(%s) as %s" % \
             (request.user.username, docid, form.cleaned_data['revision'], form.cleaned_data['user']) )
 
         user = form.cleaned_data['user'] or request.user.username
             (request.user.username, docid, form.cleaned_data['revision'], form.cleaned_data['user']) )
 
         user = form.cleaned_data['user'] or request.user.username
@@ -338,10 +338,10 @@ class DocumentHTMLHandler(BaseHandler):
                 'reason': 'not-found', 'message': e.message})
         except librarian.ValidationError, e:
             return response.InternalError().django_response({
                 'reason': 'not-found', 'message': e.message})
         except librarian.ValidationError, e:
             return response.InternalError().django_response({
-                'reason': 'xml-non-valid', 'message': e.message })
+                'reason': 'xml-non-valid', 'message': e.message or u''})
         except librarian.ParseError, e:
             return response.InternalError().django_response({
         except librarian.ParseError, e:
             return response.InternalError().django_response({
-                'reason': 'xml-parse-error', 'message': e.message })
+                'reason': 'xml-parse-error', 'message': e.message or u'' })
 
 #
 # Image Gallery
 
 #
 # Image Gallery
old mode 100644 (file)
new mode 100755 (executable)
index 31f958d..5f27a2a
@@ -44,7 +44,7 @@ class DocumentTextHandler(BaseHandler):
             user = form.cleaned_data['user'] or request.user.username
             format = form.cleaned_data['format']
 
             user = form.cleaned_data['user'] or request.user.username
             format = form.cleaned_data['format']
 
-            document = lib.document_for_rev(revision)
+            document = lib.document_for_revision(revision)
 
             if document.id != docid:
                 return response.BadRequest().django_response({
 
             if document.id != docid:
                 return response.BadRequest().django_response({
@@ -92,6 +92,7 @@ class DocumentTextHandler(BaseHandler):
     @validate_form(forms.TextUpdateForm, 'POST')
     @hglibrary
     def create(self, request, form, docid, lib):
     @validate_form(forms.TextUpdateForm, 'POST')
     @hglibrary
     def create(self, request, form, docid, lib):
+        lock = lib.lock();
         try:
             revision = form.cleaned_data['revision']
             msg = form.cleaned_data['message']
         try:
             revision = form.cleaned_data['revision']
             msg = form.cleaned_data['message']
@@ -100,14 +101,13 @@ class DocumentTextHandler(BaseHandler):
             # do not allow changing not owned documents
             # (for now... )
 
             # do not allow changing not owned documents
             # (for now... )
 
-
             if user != request.user.username:
                 return response.AccessDenied().django_response({
                     'reason': 'insufficient-priviliges',
                 })
 
             current = lib.document(docid, user)
             if user != request.user.username:
                 return response.AccessDenied().django_response({
                     'reason': 'insufficient-priviliges',
                 })
 
             current = lib.document(docid, user)
-            orig = lib.document_for_rev(revision)
+            orig = lib.document_for_revision(revision)
 
             if current != orig:
                 return response.EntityConflict().django_response({
 
             if current != orig:
                 return response.EntityConflict().django_response({
@@ -115,11 +115,15 @@ class DocumentTextHandler(BaseHandler):
                         "provided_revision": orig.revision,
                         "latest_revision": current.revision })
 
                         "provided_revision": orig.revision,
                         "latest_revision": current.revision })
 
-            if form.cleaned_data.has_key('contents'):
+            if form.cleaned_data['contents']:
                 data = form.cleaned_data['contents']
             else:
                 chunks = form.cleaned_data['chunks']
                 data = form.cleaned_data['contents']
             else:
                 chunks = form.cleaned_data['chunks']
-                xdoc = parser.WLDocument.from_string(current.data('xml'))
+                data = current.data('xml')
+                log.info(data[:600])
+                log.info(chunks)
+
+                xdoc = parser.WLDocument.from_string(data)               
                 errors = xdoc.merge_chunks(chunks)
 
                 if len(errors):
                 errors = xdoc.merge_chunks(chunks)
 
                 if len(errors):
@@ -130,6 +134,7 @@ class DocumentTextHandler(BaseHandler):
 
                 data = xdoc.serialize()
 
 
                 data = xdoc.serialize()
 
+
             # try to find any Xinclude tags
             includes = [m.groupdict()['link'] for m in (re.finditer(\
                 XINCLUDE_REGEXP, data, flags=re.UNICODE) or []) ]
             # try to find any Xinclude tags
             includes = [m.groupdict()['link'] for m in (re.finditer(\
                 XINCLUDE_REGEXP, data, flags=re.UNICODE) or []) ]
@@ -182,3 +187,5 @@ class DocumentTextHandler(BaseHandler):
         except RevisionNotFound, e:
             return response.EntityNotFound(mimetype="text/plain").\
                 django_response(e.message)
         except RevisionNotFound, e:
             return response.EntityNotFound(mimetype="text/plain").\
                 django_response(e.message)
+        finally:
+                lock.release()
index 35779d8..9a2c2aa 100755 (executable)
@@ -103,7 +103,7 @@ class MercurialDocument(wlrepo.Document):
             self.invoke_and_commit(take_action, \
                 lambda d: ("$AUTO$ File checkout.", user) )
 
             self.invoke_and_commit(take_action, \
                 lambda d: ("$AUTO$ File checkout.", user) )
 
-        return self._library.document_for_rev(fullid)
+        return self._library.document_for_revision(fullid)
 
     def up_to_date(self):
         if self.ismain():
 
     def up_to_date(self):
         if self.ismain():
index 5535a88..5e9b06e 100755 (executable)
@@ -137,6 +137,8 @@ class MercurialLibrary(wlrepo.Library):
         return fulldocid
 
     def has_revision(self, revid):
         return fulldocid
 
     def has_revision(self, revid):
+        revid = self._sanitize_string(revid)
+        
         try:
             self._hgrepo[revid]
             return True
         try:
             self._hgrepo[revid]
             return True
index d49c723..9db90be 100755 (executable)
     counter-increment: main;
 }
 
     counter-increment: main;
 }
 
+.htmlview .annotation:hover {
+    background-color: #dfdfdf;
+}
+
+.parse-warning .message {
+    color: purple;
+    font-weight: bold;
+}
+
+
+/*
+ * EDITABLE ELEMENTS
+ */
+
 .htmlview *[x-editable] {
     border: 2px solid white;
     padding: 5px;
 }
 
 /* focused editable element */
 .htmlview *[x-editable] {
     border: 2px solid white;
     padding: 5px;
 }
 
 /* focused editable element */
-.htmlview *[x-editable]:hover,
-.htmlview *[x-editable][x-open]
+.htmlview *[x-editable]:hover
 {
     background-color: #dfdfdf;
     border: 2px solid black;
 {
     background-color: #dfdfdf;
     border: 2px solid black;
+    z-index: 100;
 }
 
 }
 
-.htmlview *[x-editable] *.context-menu {
+.htmlview *[x-editable][x-open]
+{
+    visibility: hidden;
+}
+
+.htmlview *[x-editable] .context-menu {
     position: absolute;
     position: absolute;
-    top: -24px;
+    top: -28px;
     left: -2px;
     height: 24px;
     
     left: -2px;
     height: 24px;
     
     border-right: 2px solid black;    
     
     display: none;
     border-right: 2px solid black;    
     
     display: none;
+    visibility: visible;
     overflow: hidden;
     
     -moz-border-radius-topright: 5px;
     overflow: hidden;
     
     -moz-border-radius-topright: 5px;
 
     -webkit-border-top-right-radius: 5px;
     -webkit-border-top-left-radius: 5px;
 
     -webkit-border-top-right-radius: 5px;
     -webkit-border-top-left-radius: 5px;
+
+    z-index: 3000;
 }
 
 .htmlview *[x-editable] *.context-menu * {
 }
 
 .htmlview *[x-editable] *.context-menu * {
 
 .htmlview *[x-editable] *.context-menu *:hover {
     background-color: yellow;
 
 .htmlview *[x-editable] *.context-menu *:hover {
     background-color: yellow;
+    z-index: 3100;
 }
 
 }
 
-.htmlview *[x-editable]:hover *.context-menu {
+/*
+ * VISIBILITY RULES
+ */
+.htmlview *[x-editable]:hover *.default-menu {
     display: block;
 }
 
     display: block;
 }
 
-.htmlview *[x-editable][x-open] *.context-menu {
+.htmlview *[x-editable][x-open] *.default-menu {
     display: none;
 }
 
     display: none;
 }
 
-.htmlview .annotation:hover {
-    background-color: #dfdfdf;
+.htmlview *[x-editable][x-open] *.edit-menu {
+    display: block;
 }
 
 }
 
-.parse-warning .message {
-    color: purple;
-    font-weight: bold;
+.html-editarea {
+    border: 2px solid black;
+    background-color: gray;
+    padding: 1px;
+
+    z-index: 2000;
+}
+
+.html-editarea textarea
+{
+    border: 0px;
+    margin: 0px;
+    padding: 0px;
+
+    width: 100%;
+    height: 100%;
+
+    z-index: 0;
+    font-size: 10pt;
+    background-color: ivory;
 }
 }
+
+.html-editarea p.html-editarea-toolbar {
+    position: absolute;
+    background: gray;
+
+    bottom: -26px;
+    height: 24px;
+
+    left: 0px;
+    right: 0px;
+
+    border: 2px solid black;
+
+    margin: 0px;
+    padding: 0px;
+
+    z-index: 100;
+}
+
+
old mode 100644 (file)
new mode 100755 (executable)
index cebb0dc..8af8ad4
@@ -103,11 +103,11 @@ text#commit-dialog-message {
     border-right: 1px solid #999;
     height: 100%;
     background-color: #CCC;
     border-right: 1px solid #999;
     height: 100%;
     background-color: #CCC;
-    z-index: 100;
+    z-index: 5100;
 }
 
 .splitview-overlay {
 }
 
 .splitview-overlay {
-    z-index: 90;
+    z-index: 5000;
     background: #FFF;
     opacity: 0.5;
 }
     background: #FFF;
     opacity: 0.5;
 }
@@ -272,48 +272,7 @@ body#base button:hover {
     background-color: #EEE;
 }
 
     background-color: #EEE;
 }
 
-/* HTML editor interactive elements */
-
-.html-editarea {
-    border: 2px solid black;
-    background-color: gray;
-    padding: 1px;
-
-    z-index: 2000;
-}
-
-.html-editarea textarea
-{   
-   
-    border: 0px;
-    margin: 0px;    
-    padding: 0px;
-    
-    width: 100%;
-    height: 100%;
-    
-    z-index: 0;
-    font-size: 10pt;
-    background-color: ivory;
-}
-
-.html-editarea p.html-editarea-toolbar {
-    position: absolute;
-    background: gray;
-
-    bottom: -26px;
-    height: 24px;
-    
-    left: 0px;
-    right: 0px;    
-        
-    border: 2px solid black;
 
 
-    margin: 0px;
-    padding: 0px;
-
-    z-index: 100;
-}
 
 /* ================= */
 /* = Message boxes = */
 
 /* ================= */
 /* = Message boxes = */
index 7fdca39..ba2f3ce 100755 (executable)
@@ -262,7 +262,7 @@ Editor.HTMLModel = Editor.Model.extend({
         });
     },
 
         });
     },
 
-    putXMLPart: function(elem, data) {
+    putXMLPart: function(elem, data, callback) {
         var self = this;
       
         var path = elem.attr('x-pointer');
         var self = this;
       
         var path = elem.attr('x-pointer');
@@ -281,7 +281,7 @@ Editor.HTMLModel = Editor.Model.extend({
                 // format: 'nl'
             },
             success: function(htmldata) {
                 // format: 'nl'
             },
             success: function(htmldata) {
-                elem.html(htmldata);
+                callback(elem, htmldata);
                 self.set('state', 'dirty');
             }
         });
                 self.set('state', 'dirty');
             }
         });
index 3696bdc..211b33b 100755 (executable)
@@ -14,17 +14,22 @@ var HTMLView = View.extend({
         .addObserver(this, 'state', this.modelStateChanged.bind(this));
       
         $('.htmlview', this.element).html(this.model.get('data'));
         .addObserver(this, 'state', this.modelStateChanged.bind(this));
       
         $('.htmlview', this.element).html(this.model.get('data'));
+
+        this.$menuTemplate = $(render_template('html-view-frag-menu-template', this));
+        
         this.modelStateChanged('state', this.model.get('state'));
         this.modelStateChanged('state', this.model.get('state'));
-        this.model.load();       
+        this.model.load();
+
+        this.currentOpen = null;
     },
 
     modelDataChanged: function(property, value) {
         $('.htmlview', this.element).html(value);
         this.updatePrintLink();
     },
 
     modelDataChanged: function(property, value) {
         $('.htmlview', this.element).html(value);
         this.updatePrintLink();
-
+        var self = this;
+        
         $("*[x-editable]").each(function() {
         $("*[x-editable]").each(function() {
-            var e = $('<span class="context-menu"><span class="edit-button">Edytuj</span><span>Przypisy</span></span>');
-            e.appendTo(this);
+            $(this).append( self.$menuTemplate.clone() );
         });
     },
 
         });
     },
 
@@ -40,6 +45,7 @@ var HTMLView = View.extend({
         if (value == 'synced' || value == 'dirty') {
             this.unfreeze();
         } else if (value == 'unsynced') {
         if (value == 'synced' || value == 'dirty') {
             this.unfreeze();
         } else if (value == 'unsynced') {
+            if(this.currentOpen) this.closeWithoutSave(this.currentOpen);
             this.freeze('Niezsynchronizowany...');
         } else if (value == 'loading') {
             this.freeze('Ładowanie...');
             this.freeze('Niezsynchronizowany...');
         } else if (value == 'loading') {
             this.freeze('Ładowanie...');
@@ -86,81 +92,93 @@ var HTMLView = View.extend({
         this._super();
     },
 
         this._super();
     },
 
-    itemHover: function(event)
-    {
-        var $e = $(event.target);
-        if( $e.attr('x-editable') == 'editable' ) {
-            console.log('over:', $e[0]);
-            $e.css({'background-color': 'grey'});
-        }
-
-    },
-
     itemClicked: function(event) 
     {
         var self = this;
         
     itemClicked: function(event) 
     {
         var self = this;
         
-        console.log('click:', event, event.ctrlKey, event.target);
-        var editableContent = null;
+        console.log('click:', event, event.ctrlKey, event.target);        
         var $e = $(event.target);
 
         if($e.hasClass('edit-button'))
         var $e = $(event.target);
 
         if($e.hasClass('edit-button'))
-            this.openForEdit($e);
+            this.openForEdit( this.editableFor($e) );
+
+        if($e.hasClass('accept-button'))
+            this.closeWithSave( this.editableFor($e) );
+
+        if($e.hasClass('reject-button'))
+            this.closeWithoutSave( this.editableFor($e) );
     },
 
     },
 
-    openForEdit: function($e)
-    {
-        var n = 0;        
+    closeWithSave: function($e) {
+        var $edit = $e.data('edit-overlay');
+        var newText = $('textarea', $edit).val();
+
+        this.model.putXMLPart($e, newText, function($e, html) {
+            this.renderPart($e, html);
+            $edit.remove();
+            $e.removeAttr('x-open');            
+        }.bind(this) );
+        this.currentOpen = null;
+    },
+
+    closeWithoutSave: function($e) {
+        var $edit = $e.data('edit-overlay');
+        $edit.remove();
+        $e.removeAttr('x-open');
+        this.currentOpen = null;
+    },
 
 
-        while( ($e[0] != this.element[0]) && !($e.attr('x-editable'))
-            && n < 50)
+    renderPart: function($e, html) {
+            $e.html(html);
+            $e.append( this.$menuTemplate.clone() );
+    },
+
+    editableFor: function($button) 
+    {
+        var $e = $button;
+        var n = 0;
+        
+        while( ($e[0] != this.element[0]) && !($e.attr('x-editable')) && n < 50)
         {
             // console.log($e, $e.parent(), this.element);
             $e = $e.parent();
             n += 1;
         }
         {
             // console.log($e, $e.parent(), this.element);
             $e = $e.parent();
             n += 1;
         }
-      
+
         if(!$e.attr('x-editable'))
         if(!$e.attr('x-editable'))
-            return true;
+            throw Exception("Click outside of editable")
+
+        return $e;
+    },
 
 
-        var $origin = $e;
-        console.log("editable: ", $e);
+    openForEdit: function($origin)
+    {       
+        if(this.currentOpen && this.currentOpen != $origin) {
+            this.closeWithSave(this.currentOpen);
+            
+        }
     
         // start edition on this node       
     
         // start edition on this node       
-        var $overlay = $(
-        '<div class="html-editarea">\n\
-            <p class="html-editarea-toolbar">\n\
-                <button class="html-editarea-save-button" type="button">Zapisz</button>\n\
-                <button class="html-editarea-cancel-button" type="button">Anuluj</button>\n\
-            </p>\n\
-            <textarea></textarea>\n\
-        </div>');
-
-        var x = $e[0].offsetLeft;
-        var y = $e[0].offsetTop;
-        var w = $e.outerWidth();
-        var h = $e.innerHeight();
-        $overlay.css({position: 'absolute', height: 1.2*h, left: x, top: y, width: w});
-        // $e.offsetParent().append($overlay);
+        var $overlay = $('<div class="html-editarea"><textarea></textarea></div>');
 
 
+        var x = $origin[0].offsetLeft;
+        var y = $origin[0].offsetTop;
+        var w = $origin.outerWidth();
+        var h = $origin.innerHeight();
         
         
-                        
-        /* $('.html-editarea-cancel-button', $overlay).click(function() {
-            $overlay.remove();
-        });
-
-        $('.html-editarea-save-button', $overlay).click(function() {
-            $overlay.remove();
-
-            // put the part back to the model
-            self.model.putXMLPart($e, $('textarea', $overlay).val());
-        }); */
-
-        this.model.getXMLPart($e, function(path, data) {
-            $('textarea', $overlay).val(data);
-        });
+        $overlay.css({position: 'absolute', height: h, left: x, top: y, width: '95%'});
+        
+            $origin.offsetParent().append($overlay);
+            $origin.data('edit-overlay', $overlay);
+                     
+            this.model.getXMLPart($origin, function(path, data) {
+                $('textarea', $overlay).val(data);
+            });
 
 
-        $origin.attr('x-open', 'open');
+            this.currentOpen = $origin;
+            $origin.attr('x-open', 'open');
+        
+        
         return false;
     }
   
         return false;
     }
   
old mode 100644 (file)
new mode 100755 (executable)
index 151ffa6..2458e8e
                <div class="htmlview">
                </div>
        </script>       
                <div class="htmlview">
                </div>
        </script>       
+        
+        <script type="text/html" charset="utf-8" id="html-view-frag-menu-template">
+            <span class="default-menu context-menu">
+                <span class="edit-button">Edytuj</span>                
+            </span>
+            <span class="edit-menu context-menu">
+                <span class="accept-button">OK</span>
+                <span class="reject-button">Anuluj</span>
+            </span>
+        </script>
+
+
 
        <script type="text/html" charset="utf-8" id="flash-view-template">
                <div class="flashview">
 
        <script type="text/html" charset="utf-8" id="flash-view-template">
                <div class="flashview">