Merge branch 'master' of stigma:platforma
authorŁukasz Rekucki <lrekucki@gmail.com>
Thu, 8 Oct 2009 10:40:01 +0000 (12:40 +0200)
committerŁukasz Rekucki <lrekucki@gmail.com>
Thu, 8 Oct 2009 10:40:01 +0000 (12:40 +0200)
Conflicts:
project/static/css/master.css
project/static/js/models.js

16 files changed:
apps/api/handlers/library_handlers.py
apps/api/urls.py
apps/api/views.py
apps/explorer/models.py
apps/wysiwyg/tests.py [deleted file]
lib/wlrepo/__init__.py
lib/wlrepo/mercurial_backend/document.py
project/static/css/html.css
project/static/css/master.css
project/static/js/editor.js
project/static/js/editor.ui.js [deleted file]
project/static/js/models.js
project/static/js/views/html.js
project/static/js/views/xml.js
project/templates/explorer/editor.html
project/templates/wysiwyg.html

index b726067..4435fe9 100644 (file)
@@ -13,10 +13,11 @@ from datetime import date
 
 from django.core.urlresolvers import reverse
 from django.utils import simplejson as json
+from django.db import IntegrityError
 
 import librarian
 import librarian.html
-from librarian import dcparser
+from librarian import dcparser, parser
 
 from wlrepo import *
 from explorer.models import PullRequest, GalleryForDocument
@@ -229,7 +230,12 @@ class DocumentHTMLHandler(BaseHandler):
                 return response.BadRequest().django_response({'reason': 'name-mismatch',
                     'message': 'Provided revision refers, to document "%s", but provided "%s"' % (document.id, docid) })
 
-            return librarian.html.transform(document.data('xml'), is_file=False, parse_dublincore=False)
+            return librarian.html.transform(document.data('xml'), is_file=False, \
+                parse_dublincore=False, stylesheet="partial",\
+                options={
+                    "with-paths": 'boolean(1)',                    
+                })
+                
         except (EntryNotFound, RevisionNotFound), e:
             return response.EntityNotFound().django_response({
                 'reason': 'not-found', 'message': e.message})
@@ -287,6 +293,7 @@ XINCLUDE_REGEXP = r"""<(?:\w+:)?include\s+[^>]*?href=("|')wlrepo://(?P<link>[^\1
 #
 #
 #
+
 class DocumentTextHandler(BaseHandler):
     allowed_methods = ('GET', 'POST')
 
@@ -294,6 +301,8 @@ class DocumentTextHandler(BaseHandler):
     def read(self, request, docid, lib):
         """Read document as raw text"""
         revision = request.GET.get('revision', 'latest')
+        part = request.GET.get('part', False)
+        
         try:
             if revision == 'latest':
                 document = lib.document(docid)
@@ -305,22 +314,35 @@ class DocumentTextHandler(BaseHandler):
                     'message': 'Provided revision is not valid for this document'})
             
             # TODO: some finer-grained access control
-            return document.data('xml')
+            if part is False:
+                # we're done :)
+                return document.data('xml')
+            else:
+                xdoc = parser.WLDocument.from_string(document.data('xml'))
+                ptext = xdoc.part_as_text(part)
+
+                if ptext is None:
+                    return response.EntityNotFound().django_response({
+                      'reason': 'no-part-in-document'                     
+                    })
+
+                return ptext
+        except librarian.ParseError:
+            return response.EntityNotFound().django_response({
+                'reason': 'invalid-document-state',
+                'exception': type(e), 'message': e.message
+            })
         except (EntryNotFound, RevisionNotFound), e:
             return response.EntityNotFound().django_response({
-                'exception': type(e), 'message': e.message})
+                'reason': 'not-found',
+                'exception': type(e), 'message': e.message
+            })   
 
     @hglibrary
     def create(self, request, docid, lib):
         try:
-            data = request.POST['contents']
             revision = request.POST['revision']
 
-            if request.POST.has_key('message'):
-                msg = u"$USER$ " + request.POST['message']
-            else:
-                msg = u"$AUTO$ XML content update."
-
             current = lib.document(docid, request.user.username)
             orig = lib.document_for_rev(revision)
 
@@ -330,6 +352,33 @@ class DocumentTextHandler(BaseHandler):
                         "provided_revision": orig.revision,
                         "latest_revision": current.revision })
 
+            if request.POST.has_key('message'):
+                msg = u"$USER$ " + request.POST['message']
+            else:
+                msg = u"$AUTO$ XML content update."
+
+            if request.POST.has_key('contents'):
+                data = request.POST['contents']
+            else:
+                if not request.POST.has_key('chunks'):
+                    # bad request
+                    return response.BadRequest().django_response({'reason': 'invalid-arguments',
+                        'message': 'No contents nor chunks specified.'})
+
+                    # TODO: validate
+                parts = json.loads(request.POST['chunks'])                    
+                xdoc = parser.WLDocument.from_string(current.data('xml'))
+                   
+                errors = xdoc.merge_chunks(parts)
+
+                if len(errors):
+                    return response.EntityConflict().django_response({
+                            "reason": "invalid-chunks",
+                            "message": "Unable to merge following parts into the document: %s " % ",".join(errors)
+                    })
+
+                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 []) ]
@@ -498,21 +547,25 @@ class MergeHandler(BaseHandler):
                     "provided": target_rev,
                     "latest": udoc.revision })
 
-        if not request.user.has_perm('explorer.book.can_share'):
+        if not request.user.has_perm('explorer.document.can_share'):
             # User is not permitted to make a merge, right away
             # So we instead create a pull request in the database
-            prq = PullRequest(
-                comitter=request.user,
-                document=docid,
-                source_revision = str(udoc.revision),
-                status="N",
-                comment = form.cleaned_data['message'] or '$AUTO$ Document shared.'
-            )
-
-            prq.save()
-            return response.RequestAccepted().django_response(\
-                ticket_status=prq.status, \
-                ticket_uri=reverse("pullrequest_view", args=[prq.id]) )
+            try:
+                prq, created = PullRequest.get_or_create(                                        
+                    source_revision = str(udoc.revision),
+                    defaults = {
+                        'comitter': request.user,
+                        'document': docid,
+                        'status': "N",
+                        'comment': form.cleaned_data['message'] or '$AUTO$ Document shared.',
+                    }
+                )
+
+                return response.RequestAccepted().django_response(\
+                    ticket_status=prq.status, \
+                    ticket_uri=reverse("pullrequest_view", args=[prq.id]) )
+            except IntegrityError, e:
+                return response.InternalError().django_response()
 
         if form.cleaned_data['type'] == 'update':
             # update is always performed from the file branch
index 0ae1420..deac319 100644 (file)
@@ -16,6 +16,9 @@ urlpatterns = patterns('',
 #    url(r'^hello$', hello_resource, {'emitter_format': 'json'}),
 #    url(r'^hello\.(?P<emitter_format>.+)$', hello_resource),
 
+    # HTML Renderer service
+    url(r'^render$', 'api.views.render'),
+    
     # Toolbar
     url(r'^toolbar/buttons$', toolbar_buttons, {'emitter_format': 'json'},
         name="toolbar_buttons"
@@ -52,12 +55,12 @@ urlpatterns = patterns('',
 
     # XML    
     url(urlpath(r'documents', DOC, 'text', format=False),
-        document_text_resource, {'emitter_format': 'rawxml'},
+        document_text_resource, {'emitter_format': 'raw'},
         name="doctext_view"),
 
     # HTML
     url(urlpath(r'documents', DOC, 'html', format=False),
-        document_html_resource, {'emitter_format': 'rawhtml'},
+        document_html_resource, {'emitter_format': 'raw'},
         name="dochtml_view"),
 
     # DC
index 60f00ef..b96fc47 100644 (file)
@@ -1 +1,41 @@
 # Create your views here.
+
+from django.http import HttpResponse
+from librarian import html
+from lxml import etree
+from StringIO import StringIO
+import re
+
+LINE_SWAP_EXPR = re.compile(r'/\s', re.MULTILINE | re.UNICODE);
+
+def render(request):    
+    style_filename = html.get_stylesheet('partial')
+
+    data = request.POST['fragment']
+    path = request.POST['part']
+
+    base, me = path.rsplit('/', 1)
+    match = re.match(r'([^\[]+)\[(\d+)\]', me)
+    tag, pos = match.groups()
+
+    print "Redner:", path, base, tag, pos
+
+    style = etree.parse(style_filename)
+
+    data = LINE_SWAP_EXPR.sub(u'<br />\n', data)
+    doc = etree.parse( StringIO(data) )
+
+    opts = {
+        'with-paths': 'boolean(1)',
+        'base-path': "'%s'" % base,
+        'base-offset': pos,
+    }
+
+    print opts
+    
+    result = doc.xslt(style, **opts)
+
+    print result
+    
+    return HttpResponse(
+        etree.tostring(result, encoding=unicode, pretty_print=True) )
\ No newline at end of file
index 7ab6b09..23acd7f 100644 (file)
@@ -55,12 +55,12 @@ class EditorPanel(models.Model):
     def __unicode__(self):
         return self.display_name
     
-class Book(models.Model):
+class Document(models.Model):
     class Meta:
         permissions = (            
             ("can_share", "Can share documents without pull requests."),
         )
-        abstract=True
+        
     pass
 
 class PullRequest(models.Model):    
diff --git a/apps/wysiwyg/tests.py b/apps/wysiwyg/tests.py
deleted file mode 100644 (file)
index 2247054..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
-    def test_basic_addition(self):
-        """
-        Tests that 1 + 1 always equals 2.
-        """
-        self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
index ab6f319..430e59f 100644 (file)
@@ -51,7 +51,7 @@ class Document(object):
         Should be called on the user version of document. If not, it doesn nothing."""
        
     def data(self, entry):
-        """Returns the specified entry as a file-like object."""
+        """Returns the specified entry as a unicode data."""
         pass
 
     @property
index a579fb7..e714561 100644 (file)
@@ -189,7 +189,7 @@ class MercurialDocument(wlrepo.Document):
                     return False
 
                 if changed:
-                    local = local.latest()
+                    local = self.latest()._revision
                     
                 success, changed = main.merge_with(local, user=user,\
                     message=message)
index 4904a0d..336a365 100644 (file)
@@ -3,7 +3,7 @@
     font-size: 16px;
     font: Georgia, "Times New Roman", serif;
     line-height: 1.5em;
-    padding: 3em;
+    padding: 3em;    
 }
 
 .htmlview div {
 /* = Numbering = */
 /* ============= */
 .htmlview .anchor {
-    position: absolute;
-    margin: -0.25em -0.5em;
-    left: 1em;
+    position: relative;
+    margin: 0em;
+    left: -2.2em;
     color: #777;
     font-size: 12px;
     width: 2em;
     text-align: center;
-    padding: 0.25em 0.5em;
+    padding: 0.25em 0.7em;
     line-height: 1.5em;
 }
 
 /* =================== */
 /* = Custom elements = */
 /* =================== */
-.htmlview span.author {
+.htmlview .autor_utwor {
     font-size: 0.5em;
     display: block;
     line-height: 1.5em;
     margin-bottom: 0.25em;
 }
 
-.htmlview span.collection {
+.htmlview .dzielo_nadrzedne {
     font-size: 0.375em;
     display: block;
     line-height: 1.5em;
     margin-bottom: -0.25em;
 }
 
-.htmlview span.subtitle {
+.htmlview .podtytul {
     font-size: 0.5em;
     display: block;
     line-height: 1.5em;
     margin-top: -0.25em;
 }
 
-.htmlview div.didaskalia {
+.htmlview .didaskalia {
     font-style: italic;
     margin: 0.5em 0 0 1.5em;
 }
 
-.htmlview div.kwestia {
+.htmlview .kwestia {
     margin: 0.5em 0 0;
 }
 
-.htmlview div.stanza {
+.htmlview .strofa {
     margin: 1.5em 0 0;
 }
 
-.htmlview div.kwestia div.stanza {
+.htmlview .kwestia .strofa {
     margin: 0;
 }
 
-.htmlview p.paragraph {
+.htmlview .akap, .htmlview .akap_cd, .htmlview .akap_dialog {
     text-align: justify;
     margin: 1.5em 0 0;
 }
     padding-bottom: 1.5em;
 }
 
-.htmlview div.note p, .htmlview div.dedication p,
-.htmlview div.note p.paragraph, .htmlview div.dedication p.paragraph {
+.htmlview div.nota p,
+.htmlview div.dedykacja p {
     text-align: right;
     font-style: italic;
 }
 
-.htmlview hr.spacer {
+.htmlview br.sekcja_swiatlo {
     height: 3em;
-    visibility: hidden;
+    /* visibility: hidden; */
 }
 
-.htmlview hr.spacer-line {
+.htmlview hr.separator_linia {
     margin: 1.5em 0;
     border: none;
     border-bottom: 0.1em solid #000;
 }
 
-.htmlview p.spacer-asterisk {
+.htmlview p.sekcja_asterysk {
     padding: 0;
     margin: 1.5em 0;
     text-align: center;
 }
 
-.htmlview div.person-list ol {
+.htmlview div.lista_osob ol {
     list-style: none;
     padding: 0 0 0 1.5em;
 }
 
-.htmlview p.place-and-time {
+.htmlview p.miejsce_czas {
     font-style: italic;
 }
 
-.htmlview em.math, .htmlview em.foreign-word,
-.htmlview em.book-title, .htmlview em.didaskalia {
+.htmlview .mat,
+.htmlview .slowo_obce,
+.htmlview .tytul_dziela,
+.htmlview .didaskalia {
     font-style: italic;
 }
 
-.htmlview em.author-emphasis {
+.htmlview .wyroznienie {
     letter-spacing: 0.1em;
 }
 
-.htmlview em.person {
+.htmlview .osoba {
     font-style: normal;
     font-variant: small-caps;
 }
index 7c794e5..ae51e47 100644 (file)
@@ -343,7 +343,7 @@ body#base button {
     border-width: 1px;
     padding: 0px 0.5em;    
     font-family: Sans-Serif;
-    color: #000;
+    /* color: #000; */
     margin: 2px 4px;
 }
 
@@ -351,6 +351,49 @@ 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 = */
 /* ================= */
@@ -369,3 +412,4 @@ body#base button:hover {
 .critical {
     background-color: red;
 }
+
index 6918f9e..f52950f 100644 (file)
@@ -574,5 +574,5 @@ $(function() {
 
     // do the layout
     editor.loadConfig();
-    editor.setupUI();
+   editor.setupUI();
 });
diff --git a/project/static/js/editor.ui.js b/project/static/js/editor.ui.js
deleted file mode 100755 (executable)
index c8d47f6..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*\r
- * UI related Editor methods\r
- */\r
-Editor.prototype.setupUI = function() {\r
-//     // set up the UI visually and attach callbacks\r
-    var self = this;\r
-// \r
-//     var resize_start = function(event, mydata) {\r
-//         $(document).bind('mousemove', mydata, resize_changed).\r
-//         bind('mouseup', mydata, resize_stop);\r
-// \r
-//         $('.panel-overlay', mydata.root).css('display', 'block');\r
-//         return false;\r
-//     }\r
-//     var resize_changed =  function(event) {\r
-//         var old_width = parseInt(event.data.overlay.css('width'));\r
-//         var delta = event.pageX + event.data.hotspot_x - old_width;\r
-// \r
-//         if(old_width + delta < 12) delta = 12 - old_width;\r
-//         if(old_width + delta > $(window).width()) \r
-//             delta = $(window).width() - old_width;\r
-//         \r
-//         event.data.overlay.css({\r
-//             'width': old_width + delta\r
-//         });\r
-// \r
-//         if(event.data.overlay.next) {\r
-//             var left = parseInt(event.data.overlay.next.css('left'));\r
-//             event.data.overlay.next.css('left', left+delta);\r
-//         }\r
-// \r
-//         return false;\r
-//     };\r
-// \r
-//     var resize_stop = function(event) {\r
-//         $(document).unbind('mousemove', resize_changed).unbind('mouseup', resize_stop);\r
-//         // $('.panel-content', event.data.root).css('display', 'block');\r
-//         var overlays = $('.panel-content-overlay', event.data.root);\r
-//         $('.panel-content-overlay', event.data.root).each(function(i) {\r
-//             if( $(this).data('panel').hasClass('last-panel') )\r
-//                 $(this).data('panel').css({\r
-//                     'left': $(this).css('left'),\r
-//                     'right': $(this).css('right')\r
-//                 });\r
-//             else\r
-//                 $(this).data('panel').css({\r
-//                     'left': $(this).css('left'),\r
-//                     'width': $(this).css('width')\r
-//                 });\r
-//         });\r
-//         $('.panel-overlay', event.data.root).css('display', 'none');\r
-//         $(event.data.root).trigger('stopResize');\r
-//     };\r
-// \r
-//     /*\r
-//      * Prepare panels (overlays & stuff)\r
-//      */\r
-//     /* create an overlay */\r
-//     var panel_root = self.rootDiv;\r
-//     var overlay_root = $("<div class='panel-overlay'></div>");\r
-//     panel_root.append(overlay_root);\r
-// \r
-//     var prev = null;\r
-// \r
-//     $('*.panel-wrap', panel_root).each( function()\r
-//     {\r
-//         var panel = $(this);\r
-//         var handle = $('.panel-slider', panel);\r
-//         var overlay = $("<div class='panel-content-overlay panel-wrap'>&nbsp;</div>");\r
-//         overlay_root.append(overlay);\r
-//         overlay.data('panel', panel);\r
-//         overlay.data('next', null);\r
-// \r
-//         if (prev) prev.next = overlay;\r
-// \r
-//         if( panel.hasClass('last-panel') )\r
-//         {\r
-//             overlay.css({\r
-//                 'left': panel.css('left'),\r
-//                 'right': panel.css('right')\r
-//             });\r
-//         }\r
-//         else {\r
-//             overlay.css({\r
-//                 'left': panel.css('left'),\r
-//                 'width': panel.css('width')\r
-//             });\r
-//             // $.log('Has handle: ' + panel.attr('id'));\r
-//             overlay.append(handle.clone());\r
-//             /* attach the trigger */\r
-//             handle.mousedown(function(event) {\r
-//                 var touch_data = {\r
-//                     root: panel_root,\r
-//                     overlay: overlay,\r
-//                     hotspot_x: event.pageX - handle.position().left\r
-//                 };\r
-// \r
-//                 $(this).trigger('hpanel:panel-resize-start', touch_data);\r
-//                 return false;\r
-//             });\r
-//             $('.panel-content', panel).css('right',\r
-//                 (handle.outerWidth() || 10) + 'px');\r
-//             $('.panel-content-overlay', panel).css('right',\r
-//                 (handle.outerWidth() || 10) + 'px');\r
-//         };\r
-// \r
-//         prev = overlay;\r
-//     });\r
-// \r
-//     panel_root.bind('hpanel:panel-resize-start', resize_start);\r
-//     self.rootDiv.bind('stopResize', function() {\r
-//         self.savePanelOptions();      \r
-//     });\r
-//     \r
-    /*\r
-     * Connect panel actions\r
-     */\r
-    $('#panels > *.panel-wrap').each(function() {\r
-        var panelWrap = $(this);\r
-        // $.log('wrap: ', panelWrap);\r
-        var panel = new Panel(panelWrap);\r
-        panelWrap.data('ctrl', panel); // attach controllers to wraps\r
-        panel.load($('.panel-toolbar select', panelWrap).val());\r
-\r
-        $('.panel-toolbar select', panelWrap).change(function() {\r
-            var url = $(this).val();\r
-            panelWrap.data('ctrl').load(url);\r
-            self.savePanelOptions();\r
-        });\r
-\r
-        $('.panel-toolbar button.refresh-button', panelWrap).click(\r
-            function() {\r
-                panel.refresh();\r
-            } );\r
-\r
-        self.rootDiv.bind('stopResize', function() {\r
-            panel.callHook('toolbarResized');\r
-        });\r
-    });\r
-\r
-    $(document).bind('panel:contentChanged', function() {\r
-        self.onContentChanged.apply(self, arguments)\r
-    });  \r
-\r
-    /*\r
-     * Connect various buttons\r
-     */\r
-\r
-    $('#toolbar-button-quick-save').click( function (event, data) {\r
-        self.saveToBranch();\r
-    } );\r
-\r
-    $('#toolbar-button-save').click( function (event, data) {\r
-        $('#commit-dialog').jqmShow( {callback: $.fbind(self, self.saveToBranch)} );\r
-    } );\r
-\r
-    $('#toolbar-button-update').click( function (event, data) {\r
-        if (self.updateUserBranch()) {\r
-            // commit/update can be called only after proper, save\r
-            // this means all panels are clean, and will get refreshed\r
-            // do this only, when there are any changes to local branch\r
-            self.refreshPanels();\r
-        }\r
-    } );\r
-\r
-    /* COMMIT DIALOG */\r
-    $('#commit-dialog').\r
-    jqm({\r
-        modal: true,\r
-        onShow: $.fbind(self, self.loadRelatedIssues)        \r
-    });\r
-\r
-    $('#toolbar-button-commit').click( function (event, data) {\r
-        $('#commit-dialog').jqmShow( {callback: $.fbind(self, self.sendMergeRequest)} );\r
-    } );\r
-    \r
-    /* STATIC BINDS */\r
-    $('#commit-dialog-cancel-button').click(function() {\r
-        $('#commit-dialog-error-empty-message').hide();\r
-        $('#commit-dialog').jqmHide();\r
-    });   \r
-    \r
-\r
-    /* SPLIT DIALOG */\r
-    $('#split-dialog').jqm({\r
-        modal: true,\r
-        onShow: $.fbind(self, self.loadSplitDialog)\r
-    }).\r
-    jqmAddClose('button.dialog-close-button');\r
-}\r
-\r
-Editor.prototype.loadRelatedIssues = function(hash)\r
-{\r
-    var self = this;\r
-    var c = $('#commit-dialog-related-issues');\r
-\r
-    $('#commit-dialog-save-button').click( function (event, data)\r
-    {\r
-        if( $('#commit-dialog-message').val().match(/^\s*$/)) {\r
-            $('#commit-dialog-error-empty-message').fadeIn();\r
-        }\r
-        else {\r
-            $('#commit-dialog-error-empty-message').hide();\r
-            $('#commit-dialog').jqmHide();\r
-\r
-            var message = $('#commit-dialog-message').val();\r
-            $('#commit-dialog-related-issues input:checked').\r
-                each(function() { message += ' refs #' + $(this).val(); });\r
-            $.log("COMMIT APROVED", hash.t);\r
-            hash.t.callback(message);\r
-        }\r
-\r
-        return false;\r
-    });\r
-\r
-    $("div.loading-box", c).show();\r
-    $("div.fatal-error-box", c).hide();\r
-    $("div.container-box", c).hide();\r
-    \r
-    $.getJSON( c.attr('ui:ajax-src') + '?callback=?',\r
-    function(data, status)\r
-    {\r
-        var fmt = '';\r
-        $(data).each( function() {\r
-            fmt += '<label><input type="checkbox" checked="checked"'\r
-            fmt += ' value="' + this.id + '" />' + this.subject +'</label>\n'\r
-        });\r
-        $("div.container-box", c).html(fmt);\r
-        $("div.loading-box", c).hide();\r
-        $("div.container-box", c).show();        \r
-    });   \r
-    \r
-    hash.w.show();\r
-}\r
-\r
-Editor.prototype.loadSplitDialog = function(hash)\r
-{\r
-    var self = this;    \r
-    \r
-    $("div.loading-box", hash.w).show();\r
-    $("div.fatal-error-box", hash.w).hide();\r
-    $('div.container-box', hash.w).hide();\r
-    hash.w.show();\r
-\r
-    function onFailure(rq, tstat, err) {\r
-        $('div.container-box', hash.w).html('');\r
-        $("div.loading-box", hash.w).hide();\r
-        $("div.fatal-error-box", hash.w).show();\r
-        hash.t.failure();\r
-    };\r
-\r
-    function onSuccess(data, status) {\r
-        // put the form into the window\r
-        $('div.container-box', hash.w).html(data);\r
-        $("div.loading-box", hash.w).hide();\r
-        $('form input[name=splitform-splittext]', hash.w).val(hash.t.selection);\r
-        $('form input[name=splitform-fulltext]', hash.w).val(hash.t.fulltext);\r
-        $('div.container-box', hash.w).show();\r
-\r
-        // connect buttons\r
-        $('#split-dialog-button-accept').click(function() {\r
-            self.postSplitRequest(onSuccess, onFailure);\r
-            return false;\r
-        });\r
-\r
-        $('#split-dialog-button-close').click(function() {\r
-            hash.w.jqmHide();\r
-            $('div.container-box', hash.w).html('');\r
-            hash.t.failure();\r
-        });\r
-\r
-        $('#split-dialog-button-dismiss').click(function() {\r
-            hash.w.jqmHide();\r
-            $('div.container-box', hash.w).html('');\r
-            hash.t.success();\r
-        });\r
-\r
-        /* if($('#id_splitform-autoxml').is(':checked'))\r
-            $('#split-form-dc-subform').show();\r
-        else\r
-            $('#split-form-dc-subform').hide();\r
-\r
-        $('#id_splitform-autoxml').change(function() {            \r
-            if( $(this).is(':checked') )\r
-                $('#split-form-dc-subform').show();\r
-            else\r
-                $('#split-form-dc-subform').hide();\r
-        }); */\r
-    };   \r
-\r
-    $.ajax({\r
-        url: 'split',\r
-        dataType: 'html',\r
-        success: onSuccess,\r
-        error: onFailure,\r
-        type: 'GET',\r
-        data: {}\r
-    });\r
-}\r
-\r
-/* Refreshing routine */\r
-Editor.prototype.refreshPanels = function() {\r
-    var self = this;\r
-\r
-    self.allPanels().each(function() {\r
-        var panel = $(this).data('ctrl');\r
-        $.log('Refreshing: ', this, panel);\r
-        if ( panel.changed() )\r
-            panel.unmarkChanged();\r
-        else\r
-            panel.refresh();\r
-    });\r
-\r
-    $('button.provides-save').attr('disabled', 'disabled');\r
-    $('button.requires-save').removeAttr('disabled');\r
-};\r
-\r
-/*\r
- * Pop-up messages\r
- */\r
-Editor.prototype.showPopup = function(name, text, timeout)\r
-{\r
-    timeout = timeout || 4000;\r
-    var self = this;\r
-    self.popupQueue.push( [name, text, timeout] )\r
-\r
-    if( self.popupQueue.length > 1)\r
-        return;\r
-\r
-    var box = $('#message-box > #' + name);\r
-    $('*.data', box).html(text || '');\r
-    box.fadeIn(100);\r
-\r
-    if(timeout > 0)\r
-        setTimeout( $.fbind(self, self.advancePopupQueue), timeout);\r
-};\r
-\r
-Editor.prototype.advancePopupQueue = function() {\r
-    var self = this;\r
-    var elem = this.popupQueue.shift();\r
-    if(elem) {\r
-        var box = $('#message-box > #' + elem[0]);\r
-\r
-        box.fadeOut(100, function()\r
-        {\r
-            $('*.data', box).html('');\r
-\r
-            if( self.popupQueue.length > 0) {\r
-                var ibox = $('#message-box > #' + self.popupQueue[0][0]);\r
-                $('*.data', ibox).html(self.popupQueue[0][1] || '');\r
-                ibox.fadeIn(100);\r
-                if(self.popupQueue[0][2] > 0)\r
-                    setTimeout( $.fbind(self, self.advancePopupQueue), self.popupQueue[0][2]);\r
-            }\r
-        });\r
-    }\r
-};\r
-\r
-\r
index 3cd98f6..e2ee8b1 100644 (file)
@@ -1,31 +1,31 @@
 /*globals Editor fileId SplitView PanelContainerView EditorView FlashView messageCenter*/
 Editor.Model = Editor.Object.extend({
-  synced: false,
-  data: null
+    synced: false,
+    data: null
 });
 
 
 Editor.ToolbarButtonsModel = Editor.Model.extend({
-  className: 'Editor.ToolbarButtonsModel',  
-  buttons: {},
+    className: 'Editor.ToolbarButtonsModel',
+    buttons: {},
   
-  init: function() {
-    this._super();
-  },
+    init: function() {
+        this._super();
+    },
   
-  load: function() {
-    if (!this.get('buttons').length) {
-      $.ajax({
-        url: toolbarUrl,
-        dataType: 'json',
-        success: this.loadSucceeded.bind(this)
-      });
-    }
-  },
+    load: function() {
+        if (!this.get('buttons').length) {
+            $.ajax({
+                url: toolbarUrl,
+                dataType: 'json',
+                success: this.loadSucceeded.bind(this)
+            });
+        }
+    },
   
-  loadSucceeded: function(data) {
-    this.set('buttons', data);
-  }
+    loadSucceeded: function(data) {
+        this.set('buttons', data);
+    }
 });
 
 
@@ -38,382 +38,505 @@ Editor.ToolbarButtonsModel = Editor.Model.extend({
 //                            -> dirty -> updating -> updated -> synced
 //
 Editor.XMLModel = Editor.Model.extend({
-  _className: 'Editor.XMLModel',
-  serverURL: null,
-  data: '',
-  state: 'empty',
+    _className: 'Editor.XMLModel',
+    serverURL: null,
+    data: '',
+    state: 'empty',
   
-  init: function(serverURL, revision) {
-    this._super();
-    this.set('state', 'empty');
-    this.set('revision', revision);
-    this.serverURL = serverURL;
-    this.toolbarButtonsModel = new Editor.ToolbarButtonsModel();
-    this.addObserver(this, 'data', this.dataChanged.bind(this));
-  },
+    init: function(serverURL, revision) {
+        this._super();
+        this.set('state', 'empty');
+        this.set('revision', revision);
+        this.serverURL = serverURL;
+        this.toolbarButtonsModel = new Editor.ToolbarButtonsModel();
+        this.addObserver(this, 'data', this.dataChanged.bind(this));
+    },
   
-  load: function(force) {
-    if (force || this.get('state') == 'empty') {
-      this.set('state', 'loading');
-      messageCenter.addMessage('info', 'Wczytuję XML...');
-      $.ajax({
-        url: this.serverURL,
-        dataType: 'text',
-        data: {revision: this.get('revision')},
-        success: this.loadingSucceeded.bind(this),
-        error: this.loadingFailed.bind(this)
-      });
-      return true;
-    }
-    return false;
-  },
+    load: function(force) {
+        if (force || this.get('state') == 'empty') {
+            this.set('state', 'loading');
+            messageCenter.addMessage('info', 'Wczytuję XML...');
+            $.ajax({
+                url: this.serverURL,
+                dataType: 'text',
+                data: {
+                    revision: this.get('revision')
+                    },
+                success: this.loadingSucceeded.bind(this),
+                error: this.loadingFailed.bind(this)
+            });
+            return true;
+        }
+        return false;
+    },
   
-  loadingSucceeded: function(data) {
-    if (this.get('state') != 'loading') {
-      alert('erroneous state:', this.get('state'));
-    }
-    this.set('data', data);
-    this.set('state', 'synced');
-    messageCenter.addMessage('success', 'Wczytałem XML :-)');
-  },
+    loadingSucceeded: function(data) {
+        if (this.get('state') != 'loading') {
+            alert('erroneous state:', this.get('state'));
+        }
+        this.set('data', data);
+        this.set('state', 'synced');
+        messageCenter.addMessage('success', 'Wczytałem XML :-)');
+    },
   
-  loadingFailed: function() {
-    if (this.get('state') != 'loading') {
-      alert('erroneous state:', this.get('state'));
-    }
-    this.set('error', 'Nie udało się załadować panelu');
-    this.set('state', 'error');    
-    messageCenter.addMessage('error', 'Nie udało mi się wczytać XML. Spróbuj ponownie :-(');
-  },
+    loadingFailed: function() {
+        if (this.get('state') != 'loading') {
+            alert('erroneous state:', this.get('state'));
+        }
+        this.set('error', 'Nie udało się załadować panelu');
+        this.set('state', 'error');
+        messageCenter.addMessage('error', 'Nie udało mi się wczytać XML. Spróbuj ponownie :-(');
+    },
   
-  update: function(message) {
-    if (this.get('state') == 'dirty') {
-      this.set('state', 'updating');
-      messageCenter.addMessage('info', 'Zapisuję XML...');
+    update: function(message) {
+        if (this.get('state') == 'dirty') {
+            this.set('state', 'updating');
+            messageCenter.addMessage('info', 'Zapisuję XML...');
       
-      var payload = {
-        contents: this.get('data'),
-        revision: this.get('revision')
-      };
-      if (message) {
-        payload.message = message;
-      }
+            var payload = {
+                contents: this.get('data'),
+                revision: this.get('revision')
+            };
+            if (message) {
+                payload.message = message;
+            }
       
-      $.ajax({
-        url: this.serverURL,
-        type: 'post',
-        dataType: 'json',
-        data: payload,
-        success: this.updatingSucceeded.bind(this),
-        error: this.updatingFailed.bind(this)
-      });
-      return true;
-    }
-    return false;
-  },
+            $.ajax({
+                url: this.serverURL,
+                type: 'post',
+                dataType: 'json',
+                data: payload,
+                success: this.updatingSucceeded.bind(this),
+                error: this.updatingFailed.bind(this)
+            });
+            return true;
+        }
+        return false;
+    },
   
-  updatingSucceeded: function(data) {
-    if (this.get('state') != 'updating') {
-      alert('erroneous state:', this.get('state'));
-    }
-    this.set('revision', data.revision);
-    this.set('state', 'updated');
-    messageCenter.addMessage('success', 'Zapisałem XML :-)');
-  },
+    updatingSucceeded: function(data) {
+        if (this.get('state') != 'updating') {
+            alert('erroneous state:', this.get('state'));
+        }
+        this.set('revision', data.revision);
+        this.set('state', 'updated');
+        messageCenter.addMessage('success', 'Zapisałem XML :-)');
+    },
   
-  updatingFailed: function() {
-    if (this.get('state') != 'updating') {
-      alert('erroneous state:', this.get('state'));
-    }
-    messageCenter.addMessage('error', 'Nie udało mi się zapisać XML. Spróbuj ponownie :-(');
-    this.set('state', 'dirty');
-  },
+    updatingFailed: function() {
+        if (this.get('state') != 'updating') {
+            alert('erroneous state:', this.get('state'));
+        }
+        messageCenter.addMessage('error', 'Nie udało mi się zapisać XML. Spróbuj ponownie :-(');
+        this.set('state', 'dirty');
+    },
   
-  // For debbuging
-  set: function(property, value) {
-    if (property == 'state') {
-      console.log(this.description(), ':', property, '=', value);
-    }
-    return this._super(property, value);
-  },
+    // For debbuging
+    set: function(property, value) {
+        if (property == 'state') {
+            console.log(this.description(), ':', property, '=', value);
+        }
+        return this._super(property, value);
+    },
   
-  dataChanged: function(property, value) {
-    if (this.get('state') == 'synced') {
-      this.set('state', 'dirty');
-    }
-  },
+    dataChanged: function(property, value) {
+        if (this.get('state') == 'synced') {
+            this.set('state', 'dirty');
+        }
+    },
   
-  dispose: function() {
-    this.removeObserver(this);
-    this._super();
-  }
+    dispose: function() {
+        this.removeObserver(this);
+        this._super();
+    }
 });
 
 
 Editor.HTMLModel = Editor.Model.extend({
-  _className: 'Editor.HTMLModel',
-  serverURL: null,
-  data: '',
-  state: 'empty',
+    _className: 'Editor.HTMLModel',
+    dataURL: null,
+    htmlURL: null,
+    renderURL: null,
+    displaData: '',
+    xmlParts: {},
+    state: 'empty',
   
-  init: function(serverURL, revision) {
-    this._super();
-    this.set('state', 'empty');
-    this.set('revision', revision);
-    this.serverURL = serverURL;
-  },
+    init: function(htmlURL, revision, dataURL) {
+        this._super();
+        this.set('state', 'empty');
+        this.set('revision', revision);
+        this.htmlURL = htmlURL;
+        this.dataURL = dataURL;
+        this.renderURL = "http://localhost:8000/api/render";
+        this.xmlParts = {};
+    },
   
-  load: function(force) {
-    if (force || this.get('state') == 'empty') {
-      this.set('state', 'loading');
-      messageCenter.addMessage('info', 'Wczytuję HTML...');
-      $.ajax({
-        url: this.serverURL,
-        dataType: 'text',
-        data: {revision: this.get('revision')},
-        success: this.loadingSucceeded.bind(this),
-        error: this.loadingFailed.bind(this)
-      });
-    }
-  },
+    load: function(force) {
+        if (force || this.get('state') == 'empty') {
+            this.set('state', 'loading');
+
+            // load the transformed data
+            messageCenter.addMessage('info', 'Wczytuję HTML...');
+
+            $.ajax({
+                url: this.htmlURL,
+                dataType: 'text',
+                data: {
+                    revision: this.get('revision')
+                    },
+                success: this.loadingSucceeded.bind(this),
+                error: this.loadingFailed.bind(this)
+            });
+        }
+    },
   
-  loadingSucceeded: function(data) {
-    if (this.get('state') != 'loading') {
-      alert('erroneous state:', this.get('state'));
-    }
-    this.set('data', data);
-    this.set('state', 'synced');
-    messageCenter.addMessage('success', 'Wczytałem HTML :-)');
-  },
+    loadingSucceeded: function(data) {
+        if (this.get('state') != 'loading') {
+            alert('erroneous state:', this.get('state'));
+        }
+        this.set('data', data);
+        this.set('state', 'synced');
+        messageCenter.addMessage('success', 'Wczytałem HTML :-)');
+    },
   
-  loadingFailed: function() {
-    if (this.get('state') != 'loading') {
-      alert('erroneous state:', this.get('state'));
-    }
-    this.set('error', 'Nie udało się załadować panelu');
-    this.set('state', 'error');    
-    messageCenter.addMessage('error', 'Nie udało mi się wczytać HTML. Spróbuj ponownie :-(');
-  },
-
-  // For debbuging
-  set: function(property, value) {
-    if (property == 'state') {
-      console.log(this.description(), ':', property, '=', value);
+    loadingFailed: function() {
+        if (this.get('state') != 'loading') {
+            alert('erroneous state:', this.get('state'));
+        }
+        this.set('error', 'Nie udało się załadować panelu');
+        this.set('state', 'error');
+        messageCenter.addMessage('error', 'Nie udało mi się wczytać HTML. Spróbuj ponownie :-(');
+    },
+
+    getXMLPart: function(elem, callback)
+    {
+        var path = elem.attr('wl2o:path');
+        if(!this.xmlParts[path])
+            this.loadXMLPart(elem, callback);
+        else
+            callback(path, this.xmlParts[path]);
+    },
+
+    loadXMLPart: function(elem, callback)
+    {
+        var path = elem.attr('wl2o:path');
+        var self = this;
+
+        $.ajax({
+            url: this.dataURL,
+            dataType: 'text; charset=utf-8',
+            data: {
+                revision: this.get('revision'),
+                part: path
+            },
+            success: function(data) {
+                self.xmlParts[path] = data;
+                callback(path, data);
+            },
+            // TODO: error handling
+            error: function(data) {
+                console.log('Failed to load fragment');
+                callback(undefined, undefined);
+            }
+        });
+    },
+
+    putXMLPart: function(elem, data) {
+        var self = this;
+      
+        var path = elem.attr('wl2o:path');
+        this.xmlParts[path] = data;
+
+        this.set('state', 'unsynced');
+
+        /* re-render the changed fragment */
+        $.ajax({
+            url: this.renderURL,
+            type: "POST",
+            dataType: 'text; charset=utf-8',
+            data: {
+                fragment: data,
+                part: path
+            },
+            success: function(htmldata) {
+                elem.replaceWith(htmldata);
+                self.set('state', 'dirty');
+            }
+        });
+    },
+
+    update: function(message) {
+        if (this.get('state') == 'dirty') {
+            this.set('state', 'updating');
+
+            var payload = {
+                chunks: $.toJSON(this.xmlParts),
+                revision: this.get('revision')
+            };
+
+            if (message) {
+                payload.message = message;
+            }
+
+            console.log(payload)
+
+            $.ajax({
+                url: this.dataURL,
+                type: 'post',
+                dataType: 'json',
+                data: payload,
+                success: this.updatingSucceeded.bind(this),
+                error: this.updatingFailed.bind(this)
+            });
+            return true;
+        }
+        return false;
+      
+    },
+
+    updatingSucceeded: function(data) {
+        if (this.get('state') != 'updating') {
+            alert('erroneous state:', this.get('state'));
+        }
+
+        // flush the cache
+        this.xmlParts = {};
+    
+        this.set('revision', data.revision);
+        this.set('state', 'updated');
+    },
+
+    updatingFailed: function() {
+        if (this.get('state') != 'updating') {
+            alert('erroneous state:', this.get('state'));
+        }
+        messageCenter.addMessage('error', 'Uaktualnienie nie powiodło się', 'Uaktualnienie nie powiodło się');
+        this.set('state', 'dirty');
+    },
+
+    // For debbuging
+    set: function(property, value) {
+        if (property == 'state') {
+            console.log(this.description(), ':', property, '=', value);
+        }
+        return this._super(property, value);
     }
-    return this._super(property, value);
-  }
 });
 
 
 Editor.ImageGalleryModel = Editor.Model.extend({
-  _className: 'Editor.ImageGalleryModel',
-  serverURL: null,
-  data: [],
-  state: 'empty',
-
-  init: function(serverURL) {
-    this._super();
-    this.set('state', 'empty');
-    this.serverURL = serverURL;
-    // olewać data    
-    this.pages = [];
-  },
-
-  load: function(force) {
-    if (force || this.get('state') == 'empty') {
-      this.set('state', 'loading');
-      $.ajax({
-        url: this.serverURL,
-        dataType: 'json',
-        success: this.loadingSucceeded.bind(this)
-      });
-    }
-  },  
+    _className: 'Editor.ImageGalleryModel',
+    serverURL: null,
+    data: [],
+    state: 'empty',
 
-  loadingSucceeded: function(data) {
-    if (this.get('state') != 'loading') {
-      alert('erroneous state:', this.get('state'));
-    }
+    init: function(serverURL) {
+        this._super();
+        this.set('state', 'empty');
+        this.serverURL = serverURL;
+        // olewać data
+        this.pages = [];
+    },
 
-    console.log('galleries:', data);
+    load: function(force) {
+        if (force || this.get('state') == 'empty') {
+            this.set('state', 'loading');
+            $.ajax({
+                url: this.serverURL,
+                dataType: 'json',
+                success: this.loadingSucceeded.bind(this)
+            });
+        }
+    },
 
-    if (data.length === 0) {
-        this.set('data', []);
-    } else {
-        console.log('dupa');
-        this.set('data', data[0].pages);
-    }  
+    loadingSucceeded: function(data) {
+        if (this.get('state') != 'loading') {
+            alert('erroneous state:', this.get('state'));
+        }
 
-    this.set('state', 'synced');
-  },
+        console.log('galleries:', data);
 
-  set: function(property, value) {
-    if (property == 'state') {
-      console.log(this.description(), ':', property, '=', value);
+        if (data.length === 0) {
+            this.set('data', []);
+        } else {
+            console.log('dupa');
+            this.set('data', data[0].pages);
+        }
+
+        this.set('state', 'synced');
+    },
+
+    set: function(property, value) {
+        if (property == 'state') {
+            console.log(this.description(), ':', property, '=', value);
+        }
+        return this._super(property, value);
     }
-    return this._super(property, value);
-  }
 });
 
 
 Editor.DocumentModel = Editor.Model.extend({
-  _className: 'Editor.DocumentModel',
-  data: null, // name, text_url, user_revision, latest_shared_rev, parts_url, dc_url, size, merge_url
-  contentModels: {},
-  state: 'empty',
+    _className: 'Editor.DocumentModel',
+    data: null, // name, text_url, user_revision, latest_shared_rev, parts_url, dc_url, size, merge_url
+    contentModels: {},
+    state: 'empty',
   
-  init: function() {
-    this._super();
-    this.set('state', 'empty');
-    this.load();
-  },
+    init: function() {
+        this._super();
+        this.set('state', 'empty');
+        this.load();
+    },
   
-  load: function() {
-    if (this.get('state') == 'empty') {
-      this.set('state', 'loading');
-      messageCenter.addMessage('info', 'Ładuję dane dokumentu...');
-      $.ajax({
-        cache: false,
-        url: documentsUrl + fileId,
-        dataType: 'json',
-        success: this.successfulLoad.bind(this)
-      });
-    }
-  },
-  
-  successfulLoad: function(data) {
-    this.set('data', data);
-    this.set('state', 'synced');
-    this.contentModels = {
-      'xml': new Editor.XMLModel(data.text_url, data.user_revision),
-      'html': new Editor.HTMLModel(data.html_url, data.user_revision),
-      'gallery': new Editor.ImageGalleryModel(data.gallery_url)
-    };
-    for (var key in this.contentModels) {
-      this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
-    }
-    messageCenter.addMessage('success', 'Dane dokumentu zostały załadowane :-)');
-  },
-  
-  contentModelStateChanged: function(property, value, contentModel) {
-    if (value == 'dirty') {
-      this.set('state', 'dirty');
-      for (var key in this.contentModels) {
-        if (this.contentModels[key].guid() != contentModel.guid()) {
-          this.contentModels[key].set('state', 'unsynced');
+    load: function() {
+        if (this.get('state') == 'empty') {
+            this.set('state', 'loading');
+            messageCenter.addMessage('info', 'Ładuję dane dokumentu...');
+            $.ajax({
+                cache: false,
+                url: documentsUrl + fileId,
+                dataType: 'json',
+                success: this.successfulLoad.bind(this)
+            });
         }
-      }
-    } else if (value == 'updated') {
-      this.set('state', 'synced');
-      for (key in this.contentModels) {
-        if (this.contentModels[key].guid() == contentModel.guid()) {
-          this.contentModels[key].set('state', 'synced');
-          this.data.user_revision = this.contentModels[key].get('revision');
+    },
+  
+    successfulLoad: function(data) {
+        this.set('data', data);
+        this.set('state', 'synced');
+        this.contentModels = {
+            'xml': new Editor.XMLModel(data.text_url, data.user_revision),
+            'html': new Editor.HTMLModel(data.html_url, data.user_revision, data.text_url),
+            'gallery': new Editor.ImageGalleryModel(data.gallery_url)
+        };
+        for (var key in this.contentModels) {
+            this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
         }
-      }
-      for (key in this.contentModels) {
-        if (this.contentModels[key].guid() != contentModel.guid()) {
-          this.contentModels[key].set('revision', this.data.user_revision);
-          this.contentModels[key].set('state', 'empty');
+        messageCenter.addMessage('success', 'Dane dokumentu zostały załadowane :-)');
+    },
+  
+    contentModelStateChanged: function(property, value, contentModel) {
+        if (value == 'dirty') {
+            this.set('state', 'dirty');
+            for (var key in this.contentModels) {
+                if (this.contentModels[key].guid() != contentModel.guid()) {
+                    this.contentModels[key].set('state', 'unsynced');
+                }
+            }
+        } else if (value == 'updated') {
+            this.set('state', 'synced');
+            for (key in this.contentModels) {
+                if (this.contentModels[key].guid() == contentModel.guid()) {
+                    this.contentModels[key].set('state', 'synced');
+                    this.data.user_revision = this.contentModels[key].get('revision');
+                }
+            }
+            for (key in this.contentModels) {
+                if (this.contentModels[key].guid() != contentModel.guid()) {
+                    this.contentModels[key].set('revision', this.data.user_revision);
+                    this.contentModels[key].set('state', 'empty');
+                }
+            }
         }
-      }
-    }
-  },
+    },
   
-  saveDirtyContentModel: function(message) {
-    for (var key in this.contentModels) {
-      if (this.contentModels[key].get('state') == 'dirty') {
-        this.contentModels[key].update(message);
-        break;
-      }
-    }
-  },
+    saveDirtyContentModel: function(message) {
+        for (var key in this.contentModels) {
+            if (this.contentModels[key].get('state') == 'dirty') {
+                this.contentModels[key].update(message);
+                break;
+            }
+        }
+    },
   
-  update: function() {
-    this.set('state', 'loading');
-    messageCenter.addMessage('info', 'Uaktualniam dokument...');
-    $.ajax({
-      url: this.data.merge_url,
-      dataType: 'json',
-      type: 'post',
-      data: {
-        type: 'update',
-        target_revision: this.data.user_revision
-      },
-      complete: this.updateCompleted.bind(this),
-      success: function(data) { this.set('updateData', data); }.bind(this)
-    });
-  },
+    update: function() {
+        this.set('state', 'loading');
+        messageCenter.addMessage('info', 'Uaktualniam dokument...');
+        $.ajax({
+            url: this.data.merge_url,
+            dataType: 'json',
+            type: 'post',
+            data: {
+                type: 'update',
+                target_revision: this.data.user_revision
+            },
+            complete: this.updateCompleted.bind(this),
+            success: function(data) {
+                this.set('updateData', data);
+            }.bind(this)
+        });
+    },
   
-  updateCompleted: function(xhr, textStatus) {
-    console.log(xhr.status, textStatus);
-    if (xhr.status == 200) { // Sukces
-      this.data.user_revision = this.get('updateData').revision;
-      messageCenter.addMessage('info', 'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision,
-        'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision);
-      for (var key in this.contentModels) {
-        this.contentModels[key].set('revision', this.data.user_revision);
-        this.contentModels[key].set('state', 'empty');
-      }
-      messageCenter.addMessage('success', 'Uaktualniłem dokument do najnowszej wersji :-)');
-    } else if (xhr.status == 202) { // Wygenerowano PullRequest (tutaj?)
-    } else if (xhr.status == 204) { // Nic nie zmieniono
-      messageCenter.addMessage('info', 'Nic się nie zmieniło od ostatniej aktualizacji. Po co mam uaktualniać?');
-    } else if (xhr.status == 409) { // Konflikt podczas operacji
-      messageCenter.addMessage('error', 'Wystąpił konflikt podczas aktualizacji. Pędź po programistów! :-(');
-    } else if (xhr.status == 500) {
-      messageCenter.addMessage('critical', 'Błąd serwera. Pędź po programistów! :-(');
-    } 
-    this.set('state', 'synced');
-    this.set('updateData', null);
-  },
+    updateCompleted: function(xhr, textStatus) {
+        console.log(xhr.status, textStatus);
+        if (xhr.status == 200) { // Sukces
+            this.data.user_revision = this.get('updateData').revision;
+            messageCenter.addMessage('info', 'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision,
+                'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision);
+            for (var key in this.contentModels) {
+                this.contentModels[key].set('revision', this.data.user_revision);
+                this.contentModels[key].set('state', 'empty');
+            }
+            messageCenter.addMessage('success', 'Uaktualniłem dokument do najnowszej wersji :-)');
+        } else if (xhr.status == 202) { // Wygenerowano PullRequest (tutaj?)
+        } else if (xhr.status == 204) { // Nic nie zmieniono
+            messageCenter.addMessage('info', 'Nic się nie zmieniło od ostatniej aktualizacji. Po co mam uaktualniać?');
+        } else if (xhr.status == 409) { // Konflikt podczas operacji
+            messageCenter.addMessage('error', 'Wystąpił konflikt podczas aktualizacji. Pędź po programistów! :-(');
+        } else if (xhr.status == 500) {
+            messageCenter.addMessage('critical', 'Błąd serwera. Pędź po programistów! :-(');
+        }
+        this.set('state', 'synced');
+        this.set('updateData', null);
+    },
   
-  merge: function(message) {
-    this.set('state', 'loading');
-    messageCenter.addMessage('info', 'Scalam dokument z głównym repozytorium...');
-    $.ajax({
-      url: this.data.merge_url,
-      type: 'post',
-      dataType: 'json',
-      data: {
-        type: 'share',
-        target_revision: this.data.user_revision,
-        message: message
-      },
-      complete: this.mergeCompleted.bind(this),
-      success: function(data) { this.set('mergeData', data); }.bind(this)
-    });
-  },
+    merge: function(message) {
+        this.set('state', 'loading');
+        messageCenter.addMessage('info', 'Scalam dokument z głównym repozytorium...');
+        $.ajax({
+            url: this.data.merge_url,
+            type: 'post',
+            dataType: 'json',
+            data: {
+                type: 'share',
+                target_revision: this.data.user_revision,
+                message: message
+            },
+            complete: this.mergeCompleted.bind(this),
+            success: function(data) {
+                this.set('mergeData', data);
+            }.bind(this)
+        });
+    },
   
-  mergeCompleted: function(xhr, textStatus) {
-    console.log(xhr.status, textStatus);
-    if (xhr.status == 200) { // Sukces
-      this.data.user_revision = this.get('mergeData').revision;
-      for (var key in this.contentModels) {
-        this.contentModels[key].set('revision', this.data.user_revision);
-        this.contentModels[key].set('state', 'empty');
-      }
-      messageCenter.addMessage('success', 'Scaliłem dokument z głównym repozytorium :-)');
-    } else if (xhr.status == 202) { // Wygenerowano PullRequest
-      messageCenter.addMessage('success', 'Wysłałem prośbę o scalenie dokumentu z głównym repozytorium.');
-    } else if (xhr.status == 204) { // Nic nie zmieniono
-      messageCenter.addMessage('info', 'Nic się nie zmieniło od ostatniego scalenia. Po co mam scalać?');
-    } else if (xhr.status == 409) { // Konflikt podczas operacji
-      messageCenter.addMessage('error', 'Wystąpił konflikt podczas scalania. Pędź po programistów! :-(');
-    } else if (xhr.status == 500) {
-      messageCenter.addMessage('critical', 'Błąd serwera. Pędź po programistów! :-(');
-    }
-    this.set('state', 'synced');
-    this.set('mergeData', null);
-  },
+    mergeCompleted: function(xhr, textStatus) {
+        console.log(xhr.status, textStatus);
+        if (xhr.status == 200) { // Sukces
+            this.data.user_revision = this.get('mergeData').revision;
+            for (var key in this.contentModels) {
+                this.contentModels[key].set('revision', this.data.user_revision);
+                this.contentModels[key].set('state', 'empty');
+            }
+            messageCenter.addMessage('success', 'Scaliłem dokument z głównym repozytorium :-)');
+        } else if (xhr.status == 202) { // Wygenerowano PullRequest
+            messageCenter.addMessage('success', 'Wysłałem prośbę o scalenie dokumentu z głównym repozytorium.');
+        } else if (xhr.status == 204) { // Nic nie zmieniono
+            messageCenter.addMessage('info', 'Nic się nie zmieniło od ostatniego scalenia. Po co mam scalać?');
+        } else if (xhr.status == 409) { // Konflikt podczas operacji
+            messageCenter.addMessage('error', 'Wystąpił konflikt podczas scalania. Pędź po programistów! :-(');
+        } else if (xhr.status == 500) {
+            messageCenter.addMessage('critical', 'Błąd serwera. Pędź po programistów! :-(');
+        }
+        this.set('state', 'synced');
+        this.set('mergeData', null);
+    },
   
-  // For debbuging
-  set: function(property, value) {
-    if (property == 'state') {
-      console.log(this.description(), ':', property, '=', value);
+    // For debbuging
+    set: function(property, value) {
+        if (property == 'state') {
+            console.log(this.description(), ':', property, '=', value);
+        }
+        return this._super(property, value);
     }
-    return this._super(property, value);
-  }
 });
 
 
@@ -421,16 +544,16 @@ var leftPanelView, rightPanelContainer, doc;
 
 $(function()
 {
-  documentsUrl = $('#api-base-url').text() + '/';
-  toolbarUrl = $('#api-toolbar-url').text();
+    documentsUrl = $('#api-base-url').text() + '/';
+    toolbarUrl = $('#api-toolbar-url').text();
 
-  doc = new Editor.DocumentModel();
-  var editor = new EditorView('#body-wrap', doc);  
-  editor.freeze();
+    doc = new Editor.DocumentModel();
+    var editor = new EditorView('#body-wrap', doc);
+    editor.freeze();
 
-  var flashView = new FlashView('#flashview', messageCenter);
-  var splitView = new SplitView('#splitview', doc);
+    var flashView = new FlashView('#flashview', messageCenter);
+    var splitView = new SplitView('#splitview', doc);
 
-  leftPanelView = new PanelContainerView('#left-panel-container', doc);
-  rightPanelContainer = new PanelContainerView('#right-panel-container', doc); 
+    leftPanelView = new PanelContainerView('#left-panel-container', doc);
+    rightPanelContainer = new PanelContainerView('#right-panel-container', doc);
 });
index a8eb4d0..ebdf90a 100644 (file)
 /*global View render_template panels */
 var HTMLView = View.extend({
-  _className: 'HTMLView',
-  element: null,
-  model: null,
-  template: 'html-view-template',
+    _className: 'HTMLView',
+    element: null,
+    model: null,
+    template: 'html-view-template',
   
-  init: function(element, model, parent, template) {
-    this._super(element, model, template);
-    this.parent = parent;
+    init: function(element, model, parent, template) {
+        this._super(element, model, template);
+        this.parent = parent;
     
-    this.model
-      .addObserver(this, 'data', this.modelDataChanged.bind(this))
-      .addObserver(this, 'state', this.modelStateChanged.bind(this));
+        this.model
+        .addObserver(this, 'data', this.modelDataChanged.bind(this))        
+        .addObserver(this, 'state', this.modelStateChanged.bind(this));
       
-    $('.htmlview', this.element).html(this.model.get('data'));
-    this.modelStateChanged('state', this.model.get('state'));
-    this.model.load();
-  },
-  
-  modelDataChanged: function(property, value) {
-    $('.htmlview', this.element).html(value);
+        $('.htmlview', this.element).html(this.model.get('data'));
+        this.modelStateChanged('state', this.model.get('state'));
+        this.model.load();
+    },
+
+    modelDataChanged: function(property, value) {
+        $('.htmlview', this.element).html(value);
 
-    var base = this.$printLink.attr('ui:baseref');
-    this.$printLink.attr('href', base + "?revision=" + this.model.get('revision'));
-  },
+        var base = this.$printLink.attr('ui:baseref');
+        this.$printLink.attr('href', base + "?revision=" + this.model.get('revision'));
+    },
   
-  modelStateChanged: function(property, value) {
-    if (value == 'synced' || value == 'dirty') {
-      this.unfreeze();
-    } else if (value == 'unsynced') {
-      this.freeze('Niezsynchronizowany...');
-    } else if (value == 'loading') {
-      this.freeze('Ładowanie...');
-    } else if (value == 'saving') {
-      this.freeze('Zapisywanie...');
-    } else if (value == 'error') {
-      this.freeze(this.model.get('error'));
-    }
-  },
+    modelStateChanged: function(property, value) {
+        if (value == 'synced' || value == 'dirty') {
+            this.unfreeze();
+        } else if (value == 'unsynced') {
+            this.freeze('Niezsynchronizowany...');
+        } else if (value == 'loading') {
+            this.freeze('Ładowanie...');
+        } else if (value == 'saving') {
+            this.freeze('Zapisywanie...');
+        } else if (value == 'error') {
+            this.freeze(this.model.get('error'));
+        }
+    },
 
+    render: function() {
+        this.element.unbind('click');
 
-  render: function() {
-      if(this.$printLink) this.$printLink.unbind();
-      this._super();
-      this.$printLink = $('.html-print-link', this.element);
-  },
+        if(this.$printLink) this.$printLink.unbind();
+        this._super();
+        this.$printLink = $('.html-print-link', this.element);
+
+        this.element.bind('click', this.itemClicked.bind(this));
+    },
+  
+    reload: function() {
+        this.model.load(true);
+    },
   
-  reload: function() {
-    this.model.load(true);
-  },
+    dispose: function() {
+        this.model.removeObserver(this);
+        this._super();
+    },
+
+    itemClicked: function(event) 
+    {
+        var self = this;
+        
+        console.log('click:', event, event.ctrlKey, event.target);
+        var editableContent = null;
+        var $e = $(event.target);
+
+        var n = 0;
+
+        while( ($e[0] != this.element[0]) && !($e.attr('wl2o:editable'))
+            && n < 50)
+        {
+            // console.log($e, $e.parent(), this.element);
+            $e = $e.parent();
+            n += 1;
+        }
+      
+        if(!$e.attr('wl2o:editable'))
+            return true;
+    
+        // 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: h, left: "5%", top: y, width: "90%"});
+        $e.offsetParent().append($overlay);
+
+        // load the original XML content
+        console.log($e, $e.offsetParent(), $overlay);
+                        
+        $('.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());
+        });
+
+        $('textarea', $overlay).focus(function() {
+            $overlay.css('z-index', 3000);
+        }).blur(function() {
+            $overlay.css('z-index', 2000);
+        });
+
+        this.model.getXMLPart($e, function(path, data) {
+            $('textarea', $overlay).val(data);
+        });
+        
+        return false;
+    }
   
-  dispose: function() {
-    this.model.removeObserver(this);
-    this._super();
-  }
 });
 
 // Register view
index 0215472..00547d1 100644 (file)
@@ -102,7 +102,7 @@ var XMLView = View.extend({
            || (code >= 65 && code <= 90)) ) return null;
 
         var ch = String.fromCharCode(code & 0xff).toLowerCase();
-        console.log(ch.charCodeAt(0), '#', buttons);
+        /* # console.log(ch.charCodeAt(0), '#', buttons); */
 
         var buttons = $('.buttontoolbarview-button[title='+ch+']', this.element);
         var mod = 0;
@@ -129,8 +129,7 @@ var XMLView = View.extend({
     },
 
     isHotkey: function() {
-        console.log(arguments);
-        
+        /* console.log(arguments); */
         if(this.getHotkey.apply(this, arguments))
             return true;
         else
index 620d853..b338e6d 100644 (file)
@@ -13,6 +13,7 @@
        {# Libraries #}
     <script src="{{STATIC_URL}}js/lib/codemirror/codemirror.js" type="text/javascript" charset="utf-8"></script>
        <script src="{{STATIC_URL}}js/lib/jquery.modal.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{STATIC_URL}}js/lib/jquery.json.js" type="text/javascript" charset="utf-8"></script>
        {# Scriptlets #}
        <script src="{{STATIC_URL}}js/button_scripts.js" type="text/javascript" charset="utf-8"></script>
        
@@ -58,7 +59,7 @@
                 
                <div class="htmlview">
                </div>
-       </script>
+       </script>       
 
        <script type="text/html" charset="utf-8" id="flash-view-template">
                <div class="flashview">
index ec6eaed..a592bf1 100644 (file)
@@ -4,12 +4,7 @@
 <h1>Wysiwyg editor</h1>
 <div>This part is not editable!</div>
 <div id="loremIpsum">
-
- {% for a,b in listA,listB %}
-
- {{ a }} / {{ b }}
- {% endfor %}
-
 <p>
 <p>Lorem <b>ipsum</b> dolor sit amet, consectetur adipiscing elit.
     Suspendisse a urna eu enim rutrum elementum nec sed nibh. Quisque sed tortor