From 91a84926407f9f10739b2423c449bc98a57ea424 Mon Sep 17 00:00:00 2001 From: Lukasz Date: Mon, 26 Oct 2009 05:37:26 -0400 Subject: [PATCH 1/1] Edytor HTML znow powinien dzialac. --- apps/api/handlers/library_handlers.py | 6 +- apps/api/handlers/text_handler.py | 17 ++- lib/wlrepo/mercurial_backend/document.py | 2 +- lib/wlrepo/mercurial_backend/library.py | 2 + platforma/static/css/html.css | 85 +++++++++++++-- platforma/static/css/master.css | 45 +------- platforma/static/js/models.js | 4 +- platforma/static/js/views/html.js | 132 +++++++++++++---------- platforma/templates/explorer/editor.html | 12 +++ 9 files changed, 183 insertions(+), 122 deletions(-) mode change 100644 => 100755 apps/api/handlers/text_handler.py mode change 100644 => 100755 platforma/static/css/master.css mode change 100644 => 100755 platforma/templates/explorer/editor.html diff --git a/apps/api/handlers/library_handlers.py b/apps/api/handlers/library_handlers.py index 0a45a0b1..8f8f2bc0 100755 --- a/apps/api/handlers/library_handlers.py +++ b/apps/api/handlers/library_handlers.py @@ -231,7 +231,7 @@ class DocumentHandler(BaseHandler): @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 @@ -338,10 +338,10 @@ class DocumentHTMLHandler(BaseHandler): '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({ - 'reason': 'xml-parse-error', 'message': e.message }) + 'reason': 'xml-parse-error', 'message': e.message or u'' }) # # Image Gallery diff --git a/apps/api/handlers/text_handler.py b/apps/api/handlers/text_handler.py old mode 100644 new mode 100755 index 31f958da..5f27a2ab --- a/apps/api/handlers/text_handler.py +++ b/apps/api/handlers/text_handler.py @@ -44,7 +44,7 @@ class DocumentTextHandler(BaseHandler): 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({ @@ -92,6 +92,7 @@ class DocumentTextHandler(BaseHandler): @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'] @@ -100,14 +101,13 @@ class DocumentTextHandler(BaseHandler): # 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) - orig = lib.document_for_rev(revision) + orig = lib.document_for_revision(revision) if current != orig: return response.EntityConflict().django_response({ @@ -115,11 +115,15 @@ class DocumentTextHandler(BaseHandler): "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'] - 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): @@ -130,6 +134,7 @@ class DocumentTextHandler(BaseHandler): 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 []) ] @@ -182,3 +187,5 @@ class DocumentTextHandler(BaseHandler): except RevisionNotFound, e: return response.EntityNotFound(mimetype="text/plain").\ django_response(e.message) + finally: + lock.release() diff --git a/lib/wlrepo/mercurial_backend/document.py b/lib/wlrepo/mercurial_backend/document.py index 35779d82..9a2c2aa2 100755 --- a/lib/wlrepo/mercurial_backend/document.py +++ b/lib/wlrepo/mercurial_backend/document.py @@ -103,7 +103,7 @@ class MercurialDocument(wlrepo.Document): 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(): diff --git a/lib/wlrepo/mercurial_backend/library.py b/lib/wlrepo/mercurial_backend/library.py index 5535a88e..5e9b06ec 100755 --- a/lib/wlrepo/mercurial_backend/library.py +++ b/lib/wlrepo/mercurial_backend/library.py @@ -137,6 +137,8 @@ class MercurialLibrary(wlrepo.Library): return fulldocid def has_revision(self, revid): + revid = self._sanitize_string(revid) + try: self._hgrepo[revid] return True diff --git a/platforma/static/css/html.css b/platforma/static/css/html.css index d49c7231..9db90bed 100755 --- a/platforma/static/css/html.css +++ b/platforma/static/css/html.css @@ -246,22 +246,41 @@ 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]:hover, -.htmlview *[x-editable][x-open] +.htmlview *[x-editable]:hover { 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; - top: -24px; + top: -28px; left: -2px; height: 24px; @@ -281,6 +300,7 @@ border-right: 2px solid black; display: none; + visibility: visible; overflow: hidden; -moz-border-radius-topright: 5px; @@ -288,6 +308,8 @@ -webkit-border-top-right-radius: 5px; -webkit-border-top-left-radius: 5px; + + z-index: 3000; } .htmlview *[x-editable] *.context-menu * { @@ -296,21 +318,62 @@ .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; } -.htmlview *[x-editable][x-open] *.context-menu { +.htmlview *[x-editable][x-open] *.default-menu { 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; +} + + diff --git a/platforma/static/css/master.css b/platforma/static/css/master.css old mode 100644 new mode 100755 index cebb0dc4..8af8ad48 --- a/platforma/static/css/master.css +++ b/platforma/static/css/master.css @@ -103,11 +103,11 @@ text#commit-dialog-message { border-right: 1px solid #999; height: 100%; background-color: #CCC; - z-index: 100; + z-index: 5100; } .splitview-overlay { - z-index: 90; + z-index: 5000; background: #FFF; opacity: 0.5; } @@ -272,48 +272,7 @@ body#base button:hover { 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 = */ diff --git a/platforma/static/js/models.js b/platforma/static/js/models.js index 7fdca39d..ba2f3ce3 100755 --- a/platforma/static/js/models.js +++ b/platforma/static/js/models.js @@ -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'); @@ -281,7 +281,7 @@ Editor.HTMLModel = Editor.Model.extend({ // format: 'nl' }, success: function(htmldata) { - elem.html(htmldata); + callback(elem, htmldata); self.set('state', 'dirty'); } }); diff --git a/platforma/static/js/views/html.js b/platforma/static/js/views/html.js index 3696bdc8..211b33bc 100755 --- a/platforma/static/js/views/html.js +++ b/platforma/static/js/views/html.js @@ -14,17 +14,22 @@ var HTMLView = View.extend({ .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.model.load(); + this.model.load(); + + this.currentOpen = null; }, modelDataChanged: function(property, value) { $('.htmlview', this.element).html(value); this.updatePrintLink(); - + var self = this; + $("*[x-editable]").each(function() { - var e = $('EdytujPrzypisy'); - 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(this.currentOpen) this.closeWithoutSave(this.currentOpen); this.freeze('Niezsynchronizowany...'); } else if (value == 'loading') { this.freeze('Ładowanie...'); @@ -86,81 +92,93 @@ var HTMLView = View.extend({ 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; - 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')) - 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; } - + 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 - var $overlay = $( - '
\n\ -

\n\ - \n\ - \n\ -

\n\ - \n\ -
'); - - 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 = $('
'); + 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; } diff --git a/platforma/templates/explorer/editor.html b/platforma/templates/explorer/editor.html old mode 100644 new mode 100755 index 151ffa60..2458e8e0 --- a/platforma/templates/explorer/editor.html +++ b/platforma/templates/explorer/editor.html @@ -70,6 +70,18 @@
+ + + +