Merge branch 'master' into lqc-trunk
authorLukasz Rekucki <lrekucki@gmail.com>
Sun, 8 Nov 2009 13:49:11 +0000 (14:49 +0100)
committerLukasz Rekucki <lrekucki@gmail.com>
Sun, 8 Nov 2009 13:49:11 +0000 (14:49 +0100)
18 files changed:
apps/api/handlers/library_handlers.py
apps/explorer/views.py [changed mode: 0644->0755]
platforma/static/css/html.css
platforma/static/css/master.css
platforma/static/js/button_scripts.js [changed mode: 0644->0755]
platforma/static/js/lib/codemirror/codemirror.js [changed mode: 0644->0755]
platforma/static/js/models.js
platforma/static/js/views/gallery.js [changed mode: 0644->0755]
platforma/static/js/views/html.js
platforma/static/js/views/panel_container.js [changed mode: 0644->0755]
platforma/static/js/views/split.js [changed mode: 0644->0755]
platforma/static/js/views/xml.js [changed mode: 0644->0755]
platforma/static/xsl/html2wl_client.xsl [new file with mode: 0755]
platforma/static/xsl/wl2html_client.xsl [new file with mode: 0755]
platforma/templates/base.html [changed mode: 0644->0755]
platforma/templates/explorer/editor.html
platforma/templates/renderer.html [new file with mode: 0755]
platforma/urls.py [changed mode: 0644->0755]

index 7e90e31..e2d986e 100755 (executable)
@@ -15,8 +15,8 @@ from django.db import IntegrityError
 import librarian
 import librarian.html
 import difflib
+import wlrepo 
 
-from wlrepo import *
 from explorer.models import GalleryForDocument
 
 # internal imports
@@ -151,7 +151,7 @@ class LibraryHandler(BaseHandler):
                     import traceback
                     # rollback branch creation
                     lib._rollback()
-                    raise LibraryException(traceback.format_exc())
+                    raise wlrepo.LibraryException(traceback.format_exc())
 
                 url = reverse('document_view', args=[doc.id])
 
@@ -163,12 +163,12 @@ class LibraryHandler(BaseHandler):
                     url = url )            
             finally:
                 lock.release()
-        except LibraryException, e:
+        except wlrepo.LibraryException, e:
             import traceback
             return response.InternalError().django_response({
                 "reason": traceback.format_exc()
             })
-        except DocumentAlreadyExists:
+        except wlrepo.DocumentAlreadyExists:
             # Document is already there
             return response.EntityConflict().django_response({
                 "reason": "already-exists",
@@ -178,6 +178,7 @@ class LibraryHandler(BaseHandler):
 #
 # Document Handlers
 #
+
 class DiffHandler(BaseHandler):
     allowed_methods = ('GET',)
     
@@ -222,7 +223,7 @@ class DocumentHandler(BaseHandler):
             
         try:
             doc = lib.document(docid, user, rev=rev)
-        except RevisionMismatch, e:
+        except wlrepo.RevisionMismatch, e:
             # the document exists, but the revision is bad
             return response.EntityNotFound().django_response({
                 'reason': 'revision-mismatch',
@@ -230,7 +231,7 @@ class DocumentHandler(BaseHandler):
                 'docid': docid,
                 'user': user,
             })
-        except RevisionNotFound, e:
+        except wlrepo.RevisionNotFound, e:
             # the user doesn't have this document checked out
             # or some other weird error occured
             # try to do the checkout
@@ -250,7 +251,7 @@ class DocumentHandler(BaseHandler):
                         'docid': docid,
                         'user': user,
                     })
-            except RevisionNotFound, e:
+            except wlrepo.RevisionNotFound, e:
                 return response.EntityNotFound().django_response({
                     'reason': 'document-not-found',
                     'message': e.message,
@@ -313,7 +314,7 @@ class DocumentHTMLHandler(BaseHandler):
                     "with-paths": 'boolean(1)',                    
                 })
                 
-        except (EntryNotFound, RevisionNotFound), e:
+        except (wlrepo.EntryNotFound, wlrepo.RevisionNotFound), e:
             return response.EntityNotFound().django_response({
                 'reason': 'not-found', 'message': e.message})
         except librarian.ValidationError, e:
old mode 100644 (file)
new mode 100755 (executable)
index 5ec452a..a67d27c
@@ -11,6 +11,8 @@ from django.core.urlresolvers import reverse
 from django.http import HttpResponse
 from django.utils import simplejson as json
 from django.views.generic.simple import direct_to_template
+from django.shortcuts import render_to_response
+from django.template import RequestContext
 from django.contrib.auth.decorators import login_required
 
 from explorer import forms
@@ -32,12 +34,14 @@ def display_editor(request, path):
     user = request.GET.get('user', request.user.username)
     gallery_form = forms.GalleryChoiceForm()
     
-    return direct_to_template(request, 'explorer/editor.html', extra_context={
+    return render_to_response('explorer/editor.html',
+        # mimetype="text/html",
+        dictionary = {
             'fileid': path,
             'euser': user,
-            'gallery_form': gallery_form,
-    })
-    
+            'gallery_from': gallery_form,
+        }, context_instance=RequestContext(request))
+
 #
 # View all files
 #
@@ -119,3 +123,11 @@ def pull_requests(request):
 
     return direct_to_template(request, 'manager/pull_request.html', 
         extra_context = {'objects': objects} )
+
+
+#
+# Testing
+#
+def renderer_test(request):
+    return direct_to_template(request, 'renderer.html', mimetype="application/xhtml+xml",
+        extra_context = {} )
index 9db90be..acbeac2 100755 (executable)
@@ -5,7 +5,8 @@
     font-size: 16px;
     font-family: "Georgia", "Times New Roman", serif;
     line-height: 1.5em;
-    padding: 3em;    
+    padding: 3em;
+    padding-left: 55px;
 }
 
 .htmlview * {
     text-decoration: none;
 }
 
+.htmlview a:hover {
+    text-decoration: none;
+}
+
 .htmlview h1 {
     font-size: 3em;
     margin: 1.5em 0;
     text-align: center;
     line-height: 1.5em;
     font-weight: bold;
+
+    text-transform: capitalize;
 }
 
 .htmlview h2 {
     margin: 0;
 }
 
-/* ======================== */
-/* = Footnotes and themes = */
-/* ======================== */
-.htmlview .theme-begin {
-    border-left: 0.1em solid #DDDDDD;
-    color: #777;
-    padding: 0 0.5em;
-    width: 7.5em;
-    font-style: normal;
-    font-weight: normal;
-    font-size: 16px;
-    float: right;
-    margin-right: -9.5em;
-    clear: both;
-    left: 40em;
-    line-height: 1.5em;
-    text-align: left;
-}
-
 .htmlview #footnotes div {
     margin: 1.5em 0 0 0;
 }
     margin: 1em;
 }
 
-/* Przypisy */
-.htmlview .annotation {    
-    vertical-align: super;
-    text-decoration: none;
-    font-size: 0.66em;
+ .parse-warning .message {
+    color: purple;
+    font-weight: bold;
 }
 
-.htmlview a:hover {
+
+/* Motywy */
+/* ======================== */
+/* = Footnotes and themes = */
+/* ======================== */
+
+.htmlview .begin, .htmlview .end {
+    background: green;
+}
+
+.htmlview .motyw {
+    position: absolute;
+    right: -8em;
+    
+    min-width: 5em;
+    max-width: 8em;
+
+    font-weight: normal;
+    font-size: 10pt;
+    font-variant: normal;
     text-decoration: none;
+
+    padding: 0.2em 0.2em 0.2em 0.5em;
+    
+    border: 1px solid gray;
+    border-left: 2px dotted gray;
+    border-right: none;
+    
+    z-index: 1;
+    -moz-user-select: -moz-none;
+    -webkit-user-select: none;
+    user-select: none;
 }
 
-/* .htmlview .annotation:before {
-    content: "[\2217]";
-} */
+/* 
+ * Przypisy
+ */
 
-.htmlview span.annotation:before {
+/* Znaczniki w tekście */
+.htmlview .annotation {    
+    vertical-align: super;
+    text-decoration: none;
+    font-size: 0.66em;    
+}
+
+.htmlview .annotation:before {
     content: "[" counter(main) "]";
     counter-increment: main;
 }
     background-color: #dfdfdf;
 }
 
-.parse-warning .message {
-    color: purple;
-    font-weight: bold;
+*.htmlview *.annotation-inline-box {
+    position: static;
+}
+
+/*
+ * Przypisy w tekście
+ */
+ .htmlview .annotation-inline-box > span[x-annotation-box]
+ {
+     display: none;
+     position: absolute;
+
+     max-width: 36em;
+     
+     font-size: 8pt;
+     line-height: 12pt;
+     font-weight: normal;
+     font-style: normal;
+
+     background: white;
+     border-color: gray;
+     border-width: 2px;
+     border-style: outset;
+     padding: 3px 5px;
+
+     text-decoration: none;
+     z-index: 11;
+ }
+
+/*
+ * Przypisy na końcu utworu (aktualnie nieuzywane)
+ */
+.htmlview .annotations-block {
+    counter-reset: secondary;
+}
+
+.htmlview .annotations-block .annotation-body {
+    position: relative;
+    padding-left: 2.5em;
+    padding-top: 0.2em;
+}
+
+.htmlview .annotations-block .annotation-backref {
+    position: absolute;
+    top: 0.4em;
+    left: -0.4em;
+    width: 2.5em;
+    text-align: right;
+
 }
 
+.htmlview .annotations-block .annotation-backref:before {
+    content: "[" counter(secondary) "]";
+    counter-increment: secondary;
+}
 
 /*
  * EDITABLE ELEMENTS
  */
 
-.htmlview *[x-editable] {
-    border: 2px solid white;
-    padding: 5px;
+.htmlview *[x-editable] {    
+    padding-left: 3px;
 }
 
 /* focused editable element */
-.htmlview *[x-editable]:hover
-{
-    background-color: #dfdfdf;
-    border: 2px solid black;
-    z-index: 100;
-}
+/* .htmlview *[x-editable]:hover
+{    
+    
+} */
 
 .htmlview *[x-editable][x-open]
 {
     visibility: hidden;
 }
 
-.htmlview *[x-editable] .context-menu {
+.context-menu {
     position: absolute;
-    top: -28px;
-    left: -2px;
-    height: 24px;
+    top: 0px;
+    left: -50px;
+    width: 50px;
     
     text-align: center;
-
-    font-size: 14px;
-    line-height: 24px;
+    font-size: 11px;
+    line-height: 15px;
+    
     font-weight: normal;
     font-style: normal;
 
     background-color: #dfdfdf;
+
     margin: 0px;
     padding: 0px;
+    visibility: inherit;
+    display: block;
 
-    border-top: 2px solid black;
-    border-left: 2px solid black;
-    border-right: 2px solid black;    
+    border-top: 1px solid black;
+    border-left: 1px solid black;
+    border-bottom: 1px solid black;
     
-    display: none;
-    visibility: visible;
     overflow: hidden;
     
-    -moz-border-radius-topright: 5px;
-    -moz-border-radius-topleft: 5px;
+    -moz-border-radius-topleft: 2px;
+    -moz-border-radius-bottomleft: 2px;
 
-    -webkit-border-top-right-radius: 5px;
-    -webkit-border-top-left-radius: 5px;
+    -webkit-border-top-left-radius: 2px;
+    -webkit-border-bottom-left-radius: 2px;
 
     z-index: 3000;
 }
 
-.htmlview *[x-editable] *.context-menu * {
-    padding: 5px;
+.context-menu * {
+    margin: 0px;
+    display: block;
+
+    -moz-user-select: -moz-none;
+    -webkit-user-select: none;
+
+    padding: 2px;
+    cursor: pointer;
+    border-bottom: 1px solid black;
 }
 
-.htmlview *[x-editable] *.context-menu *:hover {
-    background-color: yellow;
-    z-index: 3100;
+.context-menu *:last-child {
+    cursor: pointer;
+    border-bottom: none;
+}
+
+.context-menu *:hover {
+    background-color: orange;
 }
 
 /*
  * VISIBILITY RULES
  */
-.htmlview *[x-editable]:hover *.default-menu {
-    display: block;
+.default-menu {
+    visibility: inherit;
+    opacity: 0.2;
 }
 
-.htmlview *[x-editable][x-open] *.default-menu {
-    display: none;
+.default-menu:hover {
+    opacity: 1;
 }
 
-.htmlview *[x-editable][x-open] *.edit-menu {
-    display: block;
+.htmlview *[x-annotation-box] > .default-menu {
+    opacity: 1;
+}
+
+.htmlview *[x-editable][x-open] > .default-menu {
+    visibility: hidden;
+}
+.htmlview *[x-editable][x-open] *[x-annotation-box] > .default-menu {
+    visibility: hidden;
+}
+
+.htmlview *[x-editable] > .edit-menu {
+    visibility: hidden;
+}
+.htmlview *[x-editable] *[x-annotation-box] > .edit-menu {
+    visibility: hidden;
+}
+
+.htmlview *[x-editable][x-open] > .edit-menu {
+    visibility: visible;
+}
+.htmlview *[x-editable][x-open] *[x-annotation-box] > .edit-menu {
+    visibility: visible;
 }
 
 .html-editarea {
-    border: 2px solid black;
+    border: 0px;
     background-color: gray;
     padding: 1px;
 
 
 .html-editarea textarea
 {
-    border: 0px;
+    border: 2px solid black;
+    
     margin: 0px;
     padding: 0px;
 
     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;
-}
-
-
+}
\ No newline at end of file
index 8af8ad4..8200037 100755 (executable)
@@ -153,9 +153,9 @@ text#commit-dialog-message {
 }
 
 .view-overlay {
-    z-index: 1000;
-    background: #FFF;
-    opacity: 0.8;
+    display: none;
+    z-index: 0;
+    background: #FFF;    
     text-align: center;
     vertical-align: middle;
 
@@ -165,10 +165,11 @@ text#commit-dialog-message {
     top: 0;
     bottom: 0;
 
-    user-select: 'none';
+    /* user-select: 'none';
     -webkit-user-select: 'none';
     -khtml-user-select: 'none';
-    -moz-user-select: 'none';
+    -moz-user-select: 'none'; */
+
     overflow: 'hidden';    
 }
 
old mode 100644 (file)
new mode 100755 (executable)
index 40f45f6..4af9d72
@@ -6,6 +6,7 @@ function ScriptletCenter()
     {
         var text = this.XMLEditorSelectedText(context);
         var start_tag = '<'+params.tag;
+        var move_cursor = false;
 
         for (var attr in params.attrs) {
             start_tag += ' '+attr+'="' + params.attrs[attr] + '"';
@@ -39,14 +40,23 @@ function ScriptletCenter()
             output += token;
         }
         else {
-            output = start_tag + end_tag;
+            if(params.nocontent) {
+                output = "<"+params.tag +" />";
+            }
+            else {
+                output = start_tag + end_tag;
+                move_cursor = true;
+            }
         }
 
         this.XMLEditorReplaceSelectedText(context, output);
 
-        if (text.length == 0) {
-            this.XMLEditorMoveCursorForward(context, -params.tag.length-3);
-        }        
+        try {
+            if (move_cursor) {
+                this.XMLEditorMoveCursorForward(context, params.tag.length+2);
+            }
+        } catch(e) {}
+
     }.bind(this);
 
     this.scriptlets['lineregexp'] = function(context, params) {
old mode 100644 (file)
new mode 100755 (executable)
index 97e2657..4eb5fb7
@@ -55,9 +55,9 @@ var CodeMirror = (function(){
 
   function wrapLineNumberDiv(place) {
     return function(node) {
-      var container = document.createElement("DIV"),
-          nums = document.createElement("DIV"),
-          scroller = document.createElement("DIV");
+      var container = document.createElement("div"),
+          nums = document.createElement("div"),
+          scroller = document.createElement("div");
       container.style.position = "relative";
       nums.style.position = "absolute";
       nums.style.height = "100%";
@@ -98,7 +98,7 @@ var CodeMirror = (function(){
     function update() {
       var diff = 20 + Math.max(doc.body.offsetHeight, frame.offsetHeight) - scroller.offsetHeight;
       for (var n = Math.ceil(diff / 10); n > 0; n--) {
-        var div = document.createElement("DIV");
+        var div = document.createElement("div");
         div.appendChild(document.createTextNode(nextNum++));
         scroller.appendChild(div);
       }
@@ -120,7 +120,7 @@ var CodeMirror = (function(){
     this.options = options = options || {};
     setDefaults(options, CodeMirrorConfig);
 
-    var frame = this.frame = document.createElement("IFRAME");
+    var frame = this.frame = document.createElement("iframe");
     if (options.iframeClass) frame.className = options.iframeClass;
     frame.frameBorder = 0;
     frame.src = "javascript:false;";
index 2c36e2b..59a285a 100755 (executable)
@@ -36,87 +36,192 @@ Editor.ToolbarButtonsModel = Editor.Model.extend({
 });
 
 
-// Stany modelu:
 //
-//                  -> error -> loading
-//                 /
-// empty -> loading -> synced -> unsynced -> loading
-//                           \
-//                            -> dirty -> updating -> updated -> synced
+// HTML Document Model
 //
-Editor.XMLModel = Editor.Model.extend({
-    _className: 'Editor.XMLModel',
-    serverURL: null,
-    data: '',
+Editor.HTMLModel = Editor.Model.extend({
+    _className: 'Editor.HTMLModel',
+    textURL: null,    
     state: 'empty',
-  
-    init: function(document, serverURL) {
+
+    init: function(document, textURL) {
         this._super();
         this.set('state', 'empty');
         this.set('revision', document.get('revision'));
         this.document = document;
-        this.serverURL = serverURL;
-        this.toolbarButtonsModel = new Editor.ToolbarButtonsModel();
+
+        this.textURL = textURL;        
+
+        this.htmlXSL = null;
+        this.wlmlXSL = null;
+        this.rawText = null;
+
+        // create a parser and a serializer
+        this.parser = new DOMParser();
+        this.serializer = new XMLSerializer();
+
         this.addObserver(this, 'data', this.dataChanged.bind(this));
     },
-  
+
     load: function(force) {
         if (force || this.get('state') == 'empty') {
             this.set('state', 'loading');
-            messageCenter.addMessage('info', 'xmlload', 'Wczytuję XML...');
+            messageCenter.addMessage('info', 'xmlload', 'Wczytuję HTML...');
+
+            // request all stylesheets
             $.ajax({
-                url: this.serverURL,
+                url: documentInfo.staticURL + 'xsl/wl2html_client.xsl',
+                dataType: 'xml',                
+                success: this.htmlXSLLoadSuccess.bind(this),
+                error: this.loadingFailed.bind(this)
+            });
+
+            $.ajax({
+                url: documentInfo.staticURL + 'xsl/html2wl_client.xsl',
+                dataType: 'xml',
+                success: this.wlmlXSLLoadSuccess.bind(this),
+                error: this.loadingFailed.bind(this)
+            });
+
+            $.ajax({
+                url: this.textURL,
                 dataType: 'text',
                 data: {
                     revision: this.get('revision'),
                     user: this.document.get('user')
                     },
-                success: this.loadingSucceeded.bind(this),
+                success: this.textLoadSuccess.bind(this),
                 error: this.loadingFailed.bind(this)
             });
             return true;
         }
         return false;
     },
-  
-    loadingSucceeded: function(data) {
+
+    asWLML: function(element) 
+    {
+        console.log("Source", element);
+        var doc = this.parser.parseFromString(this.serializer.serializeToString(element), 'text/xml');
+
+        var result = this.wlmlXSL.transformToDocument(doc);
+
+        if(!result) {
+            console.log("Failed", this.wlmlXSL, doc);
+            throw "Failed to transform fragment";
+        }
+        
+        console.log("Transformed", doc, " to: ", result.documentElement);
+        return this.serializer.serializeToString(result.documentElement);
+    },
+
+    updateWithWLML: function($element, text)
+    {
+        // filter the string
+        text = text.replace(/\/\s+/g, '<br />');
+        var chunk = this.parser.parseFromString("<chunk>"+text+"</chunk>", "text/xml");
+
+        var errors = $('parsererror', chunk);
+
+        // check if chunk is parsable
+        if(errors.length > 0)
+            throw {text: errors.text(), html: errors.html()};
+        
+        var result = this.htmlXSL.transformToFragment(chunk, document);
+
+        console.log("RESULT", this.serializer.serializeToString(result));
+
+        if(!result)
+            throw "WLML->HTML transformation failed.";
+        
+        $element.replaceWith(result);
+        this.set('state', 'dirty');
+    },
+
+    createXSLT: function(xslt_doc) {
+        var p = new XSLTProcessor();
+        p.importStylesheet(xslt_doc);
+        return p;
+    },
+
+    htmlXSLLoadSuccess: function(data) 
+    {
+        try {
+            this.htmlXSL = this.createXSLT(data);
+
+            if(this.wlmlXSL && this.htmlXSL && this.rawText)
+                this.loadSuccess();
+        } catch(e) {
+            this.loadingFailed();
+        }
+    },
+
+    wlmlXSLLoadSuccess: function(data)
+    {
+        try {
+            this.wlmlXSL = this.createXSLT(data);
+
+            if(this.wlmlXSL && this.htmlXSL && this.rawText)
+                this.loadSuccess();
+        } catch(e) {
+            this.loadingFailed();
+        }
+    },
+
+    textLoadSuccess: function(data) {
+        this.rawText = data;
+
+        if(this.wlmlXSL && this.htmlXSL && this.rawText)
+                this.loadSuccess();
+    },
+
+    loadSuccess: function() {
         if (this.get('state') != 'loading') {
             alert('erroneous state:', this.get('state'));
         }
-        this.set('data', data);
+
+        // prepare text
+        var doc = null;
+        doc = this.rawText.replace(/\/\s+/g, '<br />');
+        doc = this.parser.parseFromString(doc, 'text/xml');
+        doc = this.htmlXSL.transformToFragment(doc, document).firstChild;
+
+        this.set('data', doc);
         this.set('state', 'synced');
-        messageCenter.addMessage('success', 'xmlload', 'Wczytałem XML :-)');
+        messageCenter.addMessage('success', 'xmlload', 'Wczytałem HTML :-)');
     },
-  
+
     loadingFailed: function(response)
     {
         if (this.get('state') != 'loading') {
             alert('erroneous state:', this.get('state'));
         }
-        
+
         var message = parseXHRError(response);
-        
+
         this.set('error', '<h2>Błąd przy ładowaniu XML</h2><p>'+message+'</p>');
         this.set('state', 'error');
-        messageCenter.addMessage('error', 'xmlload', 'Nie udało mi się wczytać XML. Spróbuj ponownie :-(');
+        messageCenter.addMessage('error', 'xmlload', 'Nie udało mi się wczytać HTML. Spróbuj ponownie :-(');
     },
-  
+
     save: function(message) {
         if (this.get('state') == 'dirty') {
-            this.set('state', 'updating');
-            messageCenter.addMessage('info', 'xmlsave', 'Zapisuję XML...');
-      
+            this.set('state', 'saving');
+            
+            messageCenter.addMessage('info', 'htmlsave', 'Zapisuję HTML...');
+            var wlml = this.asWLML(this.get('data'));
+
             var payload = {
-                contents: this.get('data'),
+                contents: wlml,
                 revision: this.get('revision'),
                 user: this.document.get('user')
             };
+
             if (message) {
                 payload.message = message;
             }
-      
+
             $.ajax({
-                url: this.serverURL,
+                url: this.textURL,
                 type: 'post',
                 dataType: 'json',
                 data: payload,
@@ -127,24 +232,24 @@ Editor.XMLModel = Editor.Model.extend({
         }
         return false;
     },
-  
+
     saveSucceeded: function(data) {
-        if (this.get('state') != 'updating') {
+        if (this.get('state') != 'saving') {
             alert('erroneous state:', this.get('state'));
         }
         this.set('revision', data.revision);
         this.set('state', 'updated');
-        messageCenter.addMessage('success', 'xmlsave', 'Zapisałem XML :-)');
+        messageCenter.addMessage('success', 'htmlsave', 'Zapisałem :-)');
     },
-  
+
     saveFailed: function() {
-        if (this.get('state') != 'updating') {
+        if (this.get('state') != 'saving') {
             alert('erroneous state:', this.get('state'));
         }
-        messageCenter.addMessage('error', 'xmlsave', 'Nie udało mi się zapisać XML. Spróbuj ponownie :-(');
+        messageCenter.addMessage('error', 'htmlsave', 'Nie udało mi się zapisać.');
         this.set('state', 'dirty');
     },
-  
+
     // For debbuging
     set: function(property, value) {
         if (property == 'state') {
@@ -152,13 +257,13 @@ Editor.XMLModel = Editor.Model.extend({
         }
         return this._super(property, value);
     },
-  
+
     dataChanged: function(property, value) {
         if (this.get('state') == 'synced') {
             this.set('state', 'dirty');
         }
     },
-  
+
     dispose: function() {
         this.removeObserver(this);
         this._super();
@@ -166,36 +271,36 @@ Editor.XMLModel = Editor.Model.extend({
 });
 
 
-Editor.HTMLModel = Editor.Model.extend({
-    _className: 'Editor.HTMLModel',
-    dataURL: null,
-    htmlURL: null,
-    renderURL: null,
-    displaData: '',
-    xmlParts: {},
+// Stany modelu:
+//
+//                  -> error -> loading
+//                 /
+// empty -> loading -> synced -> unsynced -> loading
+//                           \
+//                            -> dirty -> updating -> updated -> synced
+//
+Editor.XMLModel = Editor.Model.extend({
+    _className: 'Editor.XMLModel',
+    serverURL: null,
+    data: '',
     state: 'empty',
   
-    init: function(document, dataURL, htmlURL) {
+    init: function(document, serverURL) {
         this._super();
         this.set('state', 'empty');
-        this.set('revision', document.get('revision'));        
-        
+        this.set('revision', document.get('revision'));
         this.document = document;
-        this.htmlURL = htmlURL;
-        this.dataURL = dataURL;
-        this.renderURL = documentInfo.renderURL;
-        this.xmlParts = {};
+        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');
-
-            // load the transformed data
-            // messageCenter.addMessage('info', 'Wczytuję HTML...');
-
+            messageCenter.addMessage('info', 'xmlload', 'Wczytuję XML...');
             $.ajax({
-                url: this.htmlURL,
+                url: this.serverURL,
                 dataType: 'text',
                 data: {
                     revision: this.get('revision'),
@@ -204,8 +309,10 @@ Editor.HTMLModel = Editor.Model.extend({
                 success: this.loadingSucceeded.bind(this),
                 error: this.loadingFailed.bind(this)
             });
+            return true;
         }
-    },    
+        return false;
+    },
   
     loadingSucceeded: function(data) {
         if (this.get('state') != 'loading') {
@@ -213,98 +320,38 @@ Editor.HTMLModel = Editor.Model.extend({
         }
         this.set('data', data);
         this.set('state', 'synced');
+        messageCenter.addMessage('success', 'xmlload', 'Wczytałem XML :-)');
     },
   
-    loadingFailed: function(response) {
+    loadingFailed: function(response)
+    {
         if (this.get('state') != 'loading') {
             alert('erroneous state:', this.get('state'));
         }
         
-        var err = parseXHRError(response);
+        var message = parseXHRError(response);
         
-        this.set('error', '<p>Nie udało się wczytać widoku HTML: </p>' + err.error_message);
-        this.set('state', 'error');        
-    },
-
-    getXMLPart: function(elem, callback)
-    {
-        var path = elem.attr('x-pointer');
-        if(!this.xmlParts[path])
-            this.loadXMLPart(elem, callback);
-        else
-            callback(path, this.xmlParts[path]);
-    },
-
-    loadXMLPart: function(elem, callback)
-    {
-        var path = elem.attr('x-pointer');
-        var self = this;
-
-        $.ajax({
-            url: this.dataURL,
-            dataType: 'text',
-            data: {
-                revision: this.get('revision'),
-                user: this.document.get('user'),
-                chunk: path
-                // format: 'nl'
-            },
-            success: function(data) {
-                self.xmlParts[path] = data;
-                console.log(data);
-                callback(path, data);
-            },
-            // TODO: error handling
-            error: function(data) {
-                console.log('Failed to load fragment');
-                callback(undefined, undefined);
-            }
-        });
-    },
-
-    putXMLPart: function(elem, data, callback) {
-        var self = this;
-      
-        var path = elem.attr('x-pointer');
-        this.xmlParts[path] = data;
-
-        this.set('state', 'dirty');
-
-        /* re-render the changed fragment */
-        $.ajax({
-            url: this.renderURL,
-            type: "POST",
-            dataType: 'text; charset=utf-8',
-            data: {
-                fragment: data,
-                chunk: path
-                // format: 'nl'
-            },
-            success: function(htmldata) {
-                callback(elem, htmldata);
-                self.set('state', 'dirty');
-            }
-        });
+        this.set('error', '<h2>Błąd przy ładowaniu XML</h2><p>'+message+'</p>');
+        this.set('state', 'error');
+        messageCenter.addMessage('error', 'xmlload', 'Nie udało mi się wczytać XML. Spróbuj ponownie :-(');
     },
-
+  
     save: function(message) {
         if (this.get('state') == 'dirty') {
             this.set('state', 'updating');
-
+            messageCenter.addMessage('info', 'xmlsave', 'Zapisuję XML...');
+      
             var payload = {
-                chunks: $.toJSON(this.xmlParts),
+                contents: this.get('data'),
                 revision: this.get('revision'),
                 user: this.document.get('user')
             };
-
             if (message) {
                 payload.message = message;
             }
-
-            console.log(payload)
-
+      
             $.ajax({
-                url: this.dataURL,
+                url: this.serverURL,
                 type: 'post',
                 dataType: 'json',
                 data: payload,
@@ -314,38 +361,45 @@ Editor.HTMLModel = Editor.Model.extend({
             return true;
         }
         return false;
-      
     },
-
+  
     saveSucceeded: 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');
+        messageCenter.addMessage('success', 'xmlsave', 'Zapisałem XML :-)');
     },
-
+  
     saveFailed: function() {
         if (this.get('state') != 'updating') {
             alert('erroneous state:', this.get('state'));
-        }        
+        }
+        messageCenter.addMessage('error', 'xmlsave', '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);
+    },
+  
+    dataChanged: function(property, value) {
+        if (this.get('state') == 'synced') {
+            this.set('state', 'dirty');
+        }
+    },
+  
+    dispose: function() {
+        this.removeObserver(this);
+        this._super();
     }
 });
 
-
 Editor.ImageGalleryModel = Editor.Model.extend({
     _className: 'Editor.ImageGalleryModel',
     serverURL: null,
@@ -465,7 +519,7 @@ Editor.DocumentModel = Editor.Model.extend({
 
         this.contentModels = {
             'xml': new Editor.XMLModel(this, data.text_url),
-            'html': new Editor.HTMLModel(this, data.text_url, data.html_url),
+            'html': new Editor.HTMLModel(this, data.text_url),
             'gallery': new Editor.ImageGalleryModel(this, data.gallery_url)
         };        
 
@@ -538,7 +592,7 @@ Editor.DocumentModel = Editor.Model.extend({
                 revision: this.get('revision'),
                 user: this.get('user')
             },
-            complete: this.updateCompleted.bind(this)           
+            complete: this.updateCompleted.bind(this)           
         });
     },
   
old mode 100644 (file)
new mode 100755 (executable)
index a403c9e..d6844c6
@@ -10,7 +10,8 @@ var ImageGalleryView = View.extend({
   init: function(element, model, parent, template) 
   {    
     console.log("init for gallery");
-    this._super(element, model, template);
+    var submodel = model.contentModels['gallery'];
+    this._super(element, submodel, template);
     this.parent = parent;
 
     console.log("gallery model", this.model);
index 211b33b..0b1234c 100755 (executable)
@@ -6,31 +6,47 @@ var HTMLView = View.extend({
     template: 'html-view-template',
   
     init: function(element, model, parent, template) {
-        this._super(element, model, template);
-        this.parent = parent;
+        var submodel = model.contentModels['html'];
+        this._super(element, submodel, template);
+        this.parent = parent;                
     
         this.model
-        .addObserver(this, 'data', this.modelDataChanged.bind(this))        
+        .addObserver(this, 'data', this.modelDataChanged.bind(this))
         .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.modelDataChanged('data', this.model.get('data'));
+                
         this.model.load();
 
         this.currentOpen = null;
+        this.currentFocused = null;
+        this.themeBoxes = [];
     },
 
-    modelDataChanged: function(property, value) {
-        $('.htmlview', this.element).html(value);
+    modelDataChanged: function(property, value)
+    {
+        if(!value) return;
+       
+        // the xml model changed
+        var container = $('.htmlview', this.element);
+        container.empty();
+        container.append(value);
+        
         this.updatePrintLink();
-        var self = this;
         
-        $("*[x-editable]").each(function() {
-            $(this).append( self.$menuTemplate.clone() );
-        });
+    /* mark themes */
+    /* $(".theme-ref", this.$docbase).each(function() {
+            var id = $(this).attr('x-theme-class');
+
+            var end = $("span.theme-end[x-theme-class = " + id+"]");
+            var begin = $("span.theme-begin[x-theme-class = " + id+"]");
+
+            var h = $(this).outerHeight();
+
+            h = Math.max(h, end.offset().top - begin.offset().top);
+            $(this).css('height', h);
+        }); */
     },
 
     updatePrintLink: function() {
@@ -54,33 +70,77 @@ var HTMLView = View.extend({
         } else if (value == 'error') {
             this.freeze(this.model.get('error'));
             $('.xml-editor-ref', this.overlay).click(
-            function(event) {
-                console.log("Sending scroll rq.", this);
-                try {
-                    var href = $(this).attr('href').split('-');
-                    var line = parseInt(href[1]);
-                    var column = parseInt(href[2]);
+                function(event) {
+                    console.log("Sending scroll rq.", this);
+                    try {
+                        var href = $(this).attr('href').split('-');
+                        var line = parseInt(href[1]);
+                        var column = parseInt(href[2]);
                     
-                    $(document).trigger('xml-scroll-request', {line:line, column:column});
-                } catch(e) {
-                    console.log(e);
-                }
+                        $(document).trigger('xml-scroll-request', {
+                            line:line,
+                            column:column
+                        });
+                    } catch(e) {
+                        console.log(e);
+                    }
                 
-                return false;
-            });
+                    return false;
+                });
         }
     },
 
     render: function() {
-        this.element.unbind('click');
+        if(this.$docbase)
+            this.$docbase.unbind('click');
+
+        if(this.$printLink) 
+            this.$printLink.unbind();
+
+        if(this.$addThemeButton)
+            this.$addThemeButton.unbind();
 
-        if(this.$printLink) this.$printLink.unbind();
         this._super();
-        this.$printLink = $('.html-print-link', this.element);
+
+        this.$printLink = $('.htmlview-toolbar .html-print-link', this.element);
+        this.$docbase = $('.htmlview', this.element);
+        this.$addThemeButton = $('.htmlview-toolbar .html-add-motive', this.element);
+
+        this.$debugButton = $('.htmlview-toolbar .html-serialize', this.element);
+
         this.updatePrintLink();
+        this.$docbase.bind('click', this.itemClicked.bind(this));
+        this.$addThemeButton.click( this.addTheme.bind(this) );
+        this.$debugButton.click( this.serialized.bind(this) );
+    },
+
+    serialized: function() {
+        this.model.set('state', 'dirty');
+        console.log( this.model.serializer.serializeToString(this.model.get('data')) );        
+    },
+
+    renderPart: function($e, html) {
+        // exceptions aren't good, but I don't have a better idea right now
+        if($e.attr('x-annotation-box')) {
+            // replace the whole annotation
+            var $p = $e.parent();
+            $p.html(html);
+            var $box = $('*[x-annotation-box]', $p);
+            $box.append( this.$menuTemplate.clone() );
+
+            if(this.currentFocused && $p[0] == this.currentFocused[0])
+            {
+                this.currentFocused = $p;
+                $box.css({
+                    'display': 'block'
+                });
+            }
+
+            return;
+        }
 
-        this.element.bind('click', this.itemClicked.bind(this));
-        // this.element.bind('mouseover', this.itemHover.bind(this));
+        $e.html(html);
+        $e.append( this.$menuTemplate.clone() );
     },
   
     reload: function() {
@@ -99,26 +159,99 @@ var HTMLView = View.extend({
         console.log('click:', event, event.ctrlKey, event.target);        
         var $e = $(event.target);
 
-        if($e.hasClass('edit-button'))
-            this.openForEdit( this.editableFor($e) );
+        if($e.hasClass('annotation'))
+        {
+            if(this.currentOpen) return false;
+            
+            var $p = $e.parent();
+            if(this.currentFocused) 
+            {
+                console.log(this.currentFocused, $p);
+                if($p[0] == this.currentFocused[0]) {
+                    console.log('unfocus of current');
+                    this.unfocusAnnotation();
+                    return false;
+                }
+
+                console.log('switch unfocus');
+                this.unfocusAnnotation();                
+            }
+
+            this.focusAnnotation($p);
+            return false;
+        }
+
+        /*
+         * Clicking outside of focused area doesn't unfocus by default
+         *  - this greatly simplifies the whole click check
+         */
+
+        if( $e.hasClass('theme-ref') )
+        {
+            console.log($e);
+            this.selectTheme($e.attr('x-theme-class'));
+            return false;
+        }
+
+        /* other buttons */
+        try {
+            if($e.hasClass('edit-button'))
+                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) );
+        } catch(e) {
+            messageCenter.addMessage('error', "wlsave", 'Błąd:' + e.text);
+        }
+        
+        return false;
+    },
+
+    unfocusAnnotation: function()
+    {
+        if(!this.currentFocused)
+        {
+            console.log('Redundant unfocus');
+            return false;
+        }
+
+        if(this.currentOpen 
+            && this.currentOpen.is("*[x-annotation-box]")
+            && this.currentOpen.parent()[0] == this.currentFocused[0])
+            {
+            console.log("Can't unfocus open box");
+            return false;
+        }
 
-        if($e.hasClass('accept-button'))
-            this.closeWithSave( this.editableFor($e) );
+        var $box = $("*[x-annotation-box]", this.currentFocused);
+        $box.css({
+            'display': 'none'
+        });
+        // this.currentFocused.removeAttr('x-focused');
+        // this.currentFocused.hide();
+        this.currentFocused = null;
+    },
 
-        if($e.hasClass('reject-button'))
-            this.closeWithoutSave( this.editableFor($e) );
+    focusAnnotation: function($e) {
+        this.currentFocused = $e;
+        var $box = $("*[x-annotation-box]", $e);
+        $box.css({
+            'display': 'block'
+        });
+        
+    // $e.attr('x-focused', 'focused');
     },
 
     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;
+        this.model.updateWithWLML($e, newText);
+        $edit.remove();
+        this.currentOpen = null;        
     },
 
     closeWithoutSave: function($e) {
@@ -128,11 +261,6 @@ var HTMLView = View.extend({
         this.currentOpen = null;
     },
 
-    renderPart: function($e, html) {
-            $e.html(html);
-            $e.append( this.$menuTemplate.clone() );
-    },
-
     editableFor: function($button) 
     {
         var $e = $button;
@@ -148,40 +276,148 @@ var HTMLView = View.extend({
         if(!$e.attr('x-editable'))
             throw Exception("Click outside of editable")
 
+        console.log("Trigger", $button, " yields editable: ", $e);
         return $e;
     },
 
     openForEdit: function($origin)
     {       
         if(this.currentOpen && this.currentOpen != $origin) {
-            this.closeWithSave(this.currentOpen);
-            
+            this.closeWithSave(this.currentOpen);    
         }
-    
-        // start edition on this node       
-        var $overlay = $('<div class="html-editarea"><textarea></textarea></div>');
+        
+        var $box = null
 
-        var x = $origin[0].offsetLeft;
-        var y = $origin[0].offsetTop;
-        var w = $origin.outerWidth();
-        var h = $origin.innerHeight();
+        // annotations overlay their sub box - not their own box //
+        if($origin.is(".annotation-inline-box"))
+            $box = $("*[x-annotation-box]", $origin);
+        else
+            $box = $origin;
         
-        $overlay.css({position: 'absolute', height: h, left: x, top: y, width: '95%'});
+        var x = $box[0].offsetLeft;
+        var y = $box[0].offsetTop;
+        var w = $box.outerWidth();
+        var h = $box.innerHeight();
+
+        console.log("Edit origin:", $origin, " box:", $box);
+        console.log("offsetParent:", $box[0].offsetParent);
+        console.log("Dimensions: ", x, y, w , h);
+
+        // start edition on this node
+        var $overlay = $('<div class="html-editarea"><textarea></textarea></div>');
         
-            $origin.offsetParent().append($overlay);
-            $origin.data('edit-overlay', $overlay);
-                     
-            this.model.getXMLPart($origin, function(path, data) {
-                $('textarea', $overlay).val(data);
-            });
+        $overlay.css({
+            position: 'absolute',
+            height: h,
+            left: x,
+            top: y,
+            width: '95%'
+        });
+        
+        try {
+            $('textarea', $overlay).val( this.model.asWLML($origin[0]) );
+
+            if($origin.is(".annotation-inline-box"))
+            {                
+                if(this.currentFocused) {
+                    // if some other is focused
+                    if($origin[0] != this.currentFocused[0]) {
+                        this.unfocusAnnotation();
+                        this.focusAnnotation($origin);
+                    }
+                // already focues
+                }
+                else { // nothing was focused
+                    this.focusAnnotation($origin);
+                }
+            }
+            else { // this item is not focusable
+                if(this.currentFocused) this.unfocusAnnotation();
+            }
 
+            $($box[0].offsetParent).append($overlay);
+            $origin.data('edit-overlay', $overlay);
+        
             this.currentOpen = $origin;
             $origin.attr('x-open', 'open');
+        }
+        catch(e) {
+            console.log("Can't open", e);
+        }
+                
+        return false;
+    },
+
+    addTheme: function() 
+    {
+        var selection = window.getSelection();
+        var n = selection.rangeCount;
+
+        console.log("Range count:", n);
         
+        if(n == 0)
+            window.alert("Nie zaznaczono żadnego obszaru");
+
+        // for now allow only 1 range
+        if(n > 1)
+            window.alert("Zaznacz jeden obszar");
+
+
+        // from this point, we will assume that the ranges are disjoint
+        for(var i=0; i < n; i++) 
+        {
+            var range = selection.getRangeAt(i);
+            console.log(i, range.startContainer, range.endContainer);
+            var date = (new Date()).getTime();
+            var random = Math.floor(4000000000*Math.random());
+            var id = (''+date) + '-' + (''+random);
+
+            var spoint = document.createRange();
+            var epoint = document.createRange();
+
+            spoint.setStart(range.startContainer, range.startOffset);
+            epoint.setStart(range.endContainer, range.endOffset);
+
+            // insert theme-ref
+            
+            var elem = $('<span x-editable="true" x-node="motyw" class="motyw">Nowy motyw</span>');
+            elem.attr('x-attr-qname-'+id, 'id');
+            elem.attr('x-attr-value-'+id, 'm'+id);
+            spoint.insertNode(elem[0]);
+
+            // insert theme-begin
+            elem = $('<span x-node="begin" class="begin"></span>');
+            elem.attr('x-attr-qname-'+id, 'id');
+            elem.attr('x-attr-value-'+id, 'b'+id);
+            spoint.insertNode(elem[0]);
+            
+            elem = $('<span x-node="end" class="end"></span>');
+            elem.attr('x-attr-qname-'+id, 'id');
+            elem.attr('x-attr-value-'+id, 'e'+id);
+            epoint.insertNode(elem[0]);
+        }
+
+    //selection.removeAllRanges();
+    },
+
+    selectTheme: function(themeId)
+    {
+        var selection = document.getSelection();
         
-        return false;
+        // remove current selection
+        selection.removeAllRanges();
+
+        var range = document.createRange();
+        var s = $('#m'+themeId)[0];
+        var e = $('#e'+themeId)[0];
+        console.log('Selecting range:', themeId, range, s, e);
+
+        if(s && e) {
+            range.setStartAfter(s);
+            range.setEndBefore(e);
+            selection.addRange(range);
+        }
     }
-  
 });
 
 // Register view
old mode 100644 (file)
new mode 100755 (executable)
index 6dbddd9..f4bdc89
@@ -26,9 +26,8 @@ var PanelContainerView = View.extend({
     }
 
     if( value != 'empty') {
-    this.contentView = new klass($('.content-view', 
-      this.element.get(0)), this.model.contentModels[value], this);
-    $('.panel-main-toolbar .refresh', this.element.get(0)).attr('disabled', null);    
+        this.contentView = new klass($('.content-view', this.element.get(0)), this.model, this);
+        $('.panel-main-toolbar .refresh', this.element.get(0)).attr('disabled', null);    
     }
   },
   
old mode 100644 (file)
new mode 100755 (executable)
index 30eda4a..a91cab6
@@ -59,6 +59,7 @@ var SplitView = View.extend({
         left: this.element.position().left
       }).appendTo(this.element);
     this.views.css("-webkit-user-select", "none"); // Safari selects A/B text on a move
+
     this.splitbar.addClass(this.activeClass);
     this.leftViewOffset = this.leftView[0].offsetWidth - event.pageX;
     
@@ -84,6 +85,11 @@ var SplitView = View.extend({
     $(document)
       .unbind('mousemove.splitview')
       .unbind('mouseup.splitview');
+
+   //from beginResize:
+   //    this.views.css("-webkit-user-select", "none"); // Safari selects A/B text on a move
+   // Restore it!
+   this.views.css("-webkit-user-select", "auto");
   },
 
   resized: function(event) {
old mode 100644 (file)
new mode 100755 (executable)
index 6f0b6fa..0dd5453
@@ -8,8 +8,11 @@ var XMLView = View.extend({
     buttonToolbar: null,
   
     init: function(element, model, parent, template) {
-        this._super(element, model, template);
+        var submodel = model.contentModels['xml'];
+        this._super(element, submodel, template);
+
         this.parent = parent;
+
         this.buttonToolbar = new ButtonToolbarView(
             $('.xmlview-toolbar', this.element),
             this.model.toolbarButtonsModel, parent);
diff --git a/platforma/static/xsl/html2wl_client.xsl b/platforma/static/xsl/html2wl_client.xsl
new file mode 100755 (executable)
index 0000000..726a404
--- /dev/null
@@ -0,0 +1,93 @@
+<xsl:stylesheet \r
+    version="1.0"\r
+\r
+    xmlns:html="http://www.w3.org/1999/xhtml"\r
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\r
+    xmlns:dc="http://purl.org/dc/elements/1.1/"\r
+>\r
+\r
+    <xsl:output method="xml" encoding="utf-8" indent="yes"/>\r
+    <!--\r
+        Ten dokument definiuję przekształcenie odwrotne do wl2html\r
+    -->\r
+\r
+\r
+    <xsl:template match="comment()"><xsl:copy /></xsl:template>\r
+\r
+    <!-- libxslt has fuck-ed prorities -->\r
+    <!-- <xsl:template match="@*[not(starts-with(name(), 'x-')) and name() != 'class']">\r
+        <xsl:message>Boom!: <xsl:value-of select="name()" /></xsl:message>\r
+    </xsl:template> -->\r
+\r
+    <xsl:template match="@*" priority="0" />\r
+\r
+    <!-- Specjalne reguły dla przypisów -->\r
+    <xsl:template match="*[@x-annotation-box]">\r
+        <xsl:apply-templates select="node()" />\r
+    </xsl:template>\r
+\r
+    <xsl:template match="*[@x-node]">\r
+        <xsl:element name="{@x-node}" namespace="{@x-ns}">\r
+            <xsl:apply-templates select="@*" />\r
+            <xsl:apply-templates select="node()" />\r
+        </xsl:element>\r
+    </xsl:template>   \r
+\r
+    <xsl:template match="*[@x-node = 'out-of-flow-text']"><xsl:value-of select="@x-content" /></xsl:template>\r
+\r
+    <!-- Specjalne reguły dla wersów -->\r
+    <xsl:template match="*[@x-node = 'wers']">\r
+        <xsl:apply-templates select="node()" />\r
+        <xsl:if test="count(following-sibling::*[starts-with(@x-node, 'wers')]) > 0"><xsl:text>/&#x000a;</xsl:text></xsl:if>\r
+    </xsl:template>\r
+\r
+    <xsl:template match="*[starts-with(@x-node, 'wers_')]">\r
+        <xsl:element name="{@x-node}" namespace="{@x-ns}"><xsl:apply-templates select="@*|node()" /></xsl:element>\r
+        <xsl:if test="count(following-sibling::*[starts-with(@x-node, 'wers')]) > 0"><xsl:text>/&#x000a;</xsl:text></xsl:if>\r
+    </xsl:template>\r
+    \r
+    <xsl:template match="@*[starts-with(name(), 'x-attr-qname-')]">\r
+        <xsl:variable name="attr-id" select="substring-after(name(), 'x-attr-qname-')" />\r
+        <xsl:attribute name="{.}" namespace="{parent::*/@*[name() = concat('x-attr-ns-', $attr-id)]}">\r
+            <xsl:value-of select="parent::*/@*[name() = concat('x-attr-value-', $attr-id)]" />\r
+        </xsl:attribute>\r
+    </xsl:template>\r
+\r
+    <!-- upper case duplicates for the brain-dead Firefox -->\r
+\r
+    <xsl:template match="@*[starts-with(name(), 'X-ATTR-QNAME-')]">\r
+        <xsl:variable name="attr-id" select="substring-after(name(), 'X-ATTR-QNAME-')" />\r
+        <xsl:attribute name="{.}" namespace="{parent::*/@*[name() = concat('X-ATTR-NS-', $attr-id)]}">\r
+            <xsl:value-of select="parent::*/@*[name() = concat('X-ATTR-VALUE-', $attr-id)]" />\r
+        </xsl:attribute>\r
+    </xsl:template>\r
+\r
+    <xsl:template match="*[@X-ANNOTATION-BOX]">\r
+        <xsl:apply-templates select="node()" />\r
+    </xsl:template>\r
+\r
+    <xsl:template match="*[@X-NODE]">\r
+        <xsl:element name="{@X-NODE}" namespace="{@X-NS}">\r
+            <xsl:apply-templates select="@*" />\r
+            <xsl:apply-templates select="node()" />\r
+        </xsl:element>\r
+    </xsl:template>\r
+\r
+    <xsl:template match="*[@X-NODE = 'out-of-flow-text']"><xsl:value-of select="@X-CONTENT" /></xsl:template>\r
+\r
+    <!-- Specjalne reguły dla wersów -->\r
+    <xsl:template match="*[@X-NODE = 'wers']">\r
+        <xsl:apply-templates select="node()" />\r
+        <xsl:if test="count(following-sibling::*[starts-with(@X-NODE, 'wers')]) > 0"><xsl:text>/&#x000a;</xsl:text></xsl:if>\r
+    </xsl:template>\r
+\r
+    <xsl:template match="*[starts-with(@X-NODE, 'wers_')]">\r
+        <xsl:element name="{@X-NODE}" namespace="{@X-NS}"><xsl:apply-templates select="@*|node()" /></xsl:element>\r
+        <xsl:if test="count(following-sibling::*[starts-with(@X-NODE, 'wers')]) > 0"><xsl:text>/&#x000a;</xsl:text></xsl:if>\r
+    </xsl:template>\r
+\r
+    \r
+    \r
+    <xsl:template match="*" />\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/platforma/static/xsl/wl2html_client.xsl b/platforma/static/xsl/wl2html_client.xsl
new file mode 100755 (executable)
index 0000000..234ea5c
--- /dev/null
@@ -0,0 +1,754 @@
+<xsl:stylesheet version="1.0"    
+    xmlns="http://www.w3.org/1999/xhtml"    
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+    <!--
+        Dokument ten opisuje jednoznaczne przekształcenie WLML 0.1 -> XHTML.
+    -->        
+    <xsl:output method="xml" encoding="utf-8" indent="no" />
+
+    <xsl:template match="/">
+        <xsl:apply-templates select="chunk|utwor" />
+    </xsl:template>
+
+    <!--
+        Base tag for rendering a fragment of text
+    -->
+    <xsl:template match="chunk">        
+        <xsl:apply-templates select="child::node()">            
+            <xsl:with-param name="mixed" select="true()" />
+        </xsl:apply-templates>        
+    </xsl:template>
+    
+    <!--
+        Base tag for rendering the whole text 
+    -->
+
+    <xsl:template match="utwor">
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::*">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>    
+    
+    <!-- 
+        Przekształcenia poszczególnych elementów zgodnie z:            
+        http://wiki.wolnepodreczniki.pl/Lektury:Sk%C5%82ad/Tagi_sk%C5%82adu
+    -->
+
+    <!-- TAGI MASTERÓW STYLÓW
+    
+        Tagi rozpoczynające i kończące tekst utworu lirycznego o standardowej szerokości łamu:
+    -->
+
+    <xsl:template match="opowiadanie|powiesc">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="liryka_l|liryka_lp">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="dramat_wierszowany_l|dramat_wierszowany_lp|dramat_wspolczesny">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="wywiad">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <!-- 
+        *****************************
+        ELEMENTY POZA TEKSTEM GŁÓWNYM
+        *****************************
+    -->
+
+    <!--
+        Autor składanego utworu
+
+        Element strony tytułowej - lub odpowiadającej jej przestrzeni,
+        np. na stronie internetowej) :
+
+        <autor_utworu> imiona-itd.-autora-składanego-utworu </autor_utworu>
+    -->
+    <xsl:template match="autor_utworu">
+        <xsl:param name="mixed" />
+        <h2 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h2>
+    </xsl:template>
+
+    <!-- 
+        Nazwa składanego utworu
+
+        Element strony tytułowej - lub odpowiadającej jej przestrzeni,
+        np. na stronie internetowej
+
+        <nazwa_utworu> tytuł-składanego-utworu </nazwa_utworu>
+    -->
+    <xsl:template match="nazwa_utworu">
+        <xsl:param name="mixed" />
+        <h1 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h1>
+    </xsl:template>
+
+    <!--
+        Nazwa utworu nadrzędnego, w którego skład wchodzi dany utwór
+        <dzielo_nadrzedne> tytuł-dzieła-nadrzędnego </dzielo_nadrzedne>
+
+         Przykład:
+
+         <utwor>
+         <liryka_l>
+            <autor_utworu>Bruno Jasieński</autor_utworu>
+            <dzielo_nadrzedne>But w butonierce</dzielo_nadrzedne>
+            <nazwa_utworu>Deszcz</nazwa_utworu>
+            ....
+    -->
+    <xsl:template match="dzielo_nadrzedne">
+        <xsl:param name="mixed" />
+        <h2 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h2>
+    </xsl:template>
+
+    <!--
+        Podtytuł, czyli wszystkie dopiski do tytułu
+
+        Element strony tytułowej - lub odpowiadającej jej przestrzeni.
+        <podtytul> podtytuł-składanego-utworu </podtytul>
+
+        Przykład:
+        <utwor>
+            <powiesc>
+            <autor_utworu>Daniel Defoe</autor_utworu>
+            <nazwa_utworu>Robinson Crusoe</nazwa_utworu>
+            <podtytul>Jego życia losy, doświadczenia i przypadki</podtytul>
+            ...
+    -->
+    <xsl:template match="podtytul">
+        <xsl:param name="mixed" />
+        <h3 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h3>
+    </xsl:template>
+
+    <!--
+       Tagi obejmujące tekst noty poprzedzającej tekst główny (styl wieloakapitowy):
+
+        <nota><akap> tekst-noty </akap></nota> (styl wieloakapitowy)
+    -->
+
+    <xsl:template match="nota">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <!--
+        Tagi obejmujące tekst dedykacji (styl wieloakapitowy bądź wielostrofowy):
+        <dedykacja> tekst-dedykacji </dedykacja>
+    -->
+    <xsl:template match="dedykacja">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <!--
+        Tagi obejmujące tekst motta (styl wieloakapitowy bądź wielostrofowy):
+        <motto> tekst-motta </motto>
+    -->
+    <xsl:template match="motto">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="motto_podpis">
+        <xsl:param name="mixed" />
+        <p x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+    <!--
+        Tagi obejmujące listę osób poprzedzającą tekst dramatu
+          (zwykle składaną na osobnej stronie; to odmiana stylu listy):
+
+        <lista_osob> osoby </lista_osob>
+    -->
+    <xsl:template match="lista_osob">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="naglowek_listy">
+        <xsl:param name="mixed" />
+        <p x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+    <xsl:template match="lista_osoba">
+        <xsl:param name="mixed" />
+        <p x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+    <!--  Tagi obejmujące inne komentarze wprowadzające
+        przed tekstem dramatu (składane razem z listą osób):
+
+        <miejsce_czas> komentarze-wprowadzające </miejsce_czas>
+    -->
+    <xsl:template match="miejsce_czas">
+        <xsl:param name="mixed" />
+        <p x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+
+    <!--
+        ***************************
+        TAGI STYLÓW TEKSTU GŁÓWNEGO
+        ***************************
+    -->
+
+    <!--
+      Tagi nagłówka części/księgi:
+      <naglowek_czesc> nagłówek-części-lub-księgi </naglowek_czesc>
+    -->
+    <xsl:template match="naglowek_czesc">
+        <xsl:param name="mixed" />
+        <h2 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h2>
+    </xsl:template>
+
+    <!--
+      Tagi tytułu rozdziału:
+      <naglowek_rozdzial> nr-i/lub-tytuł </naglowek_rozdzial>
+    -->
+    <xsl:template match="naglowek_rozdzial">
+        <xsl:param name="mixed" />
+        <h3 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h3>
+    </xsl:template>
+
+    <!--
+      Tagi tytułu podrozdziału:
+      <naglowek_podrozdzial> nr-i/lub-podtytuł </naglowek_podrozdzial>
+    -->
+    <xsl:template match="naglowek_podrozdzial">
+        <xsl:param name="mixed" />
+        <h4 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h4>
+    </xsl:template>
+
+    <!--
+       Tagi sródtytułu:
+       <srodtytul> śródtytuł </srodtytul>
+
+       Tagi nagłówków aktów:
+       <naglowek_akt> nagłówek-aktu </naglowek_akt>
+    -->
+
+    <xsl:template match="srodtytul">
+        <xsl:param name="mixed" />
+        <h2 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h2>
+    </xsl:template>
+
+    <xsl:template match="naglowek_akt">
+        <xsl:param name="mixed" />
+        <h2 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h2>
+    </xsl:template>
+
+    <!--
+      Tagi nagłówków scen:
+      <naglowek_scena> nagłówek-sceny </naglowek_scena>
+    -->
+
+    <xsl:template match="naglowek_scena">
+        <xsl:param name="mixed" />
+        <h3 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h3>
+    </xsl:template>
+    
+    <xsl:template match="naglowek_osoba">
+        <xsl:param name="mixed" />
+        <h4 x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </h4>
+    </xsl:template>
+
+    <!--
+       ************************
+       Bloki w tekście głównym
+       ************************
+    -->
+    
+    <xsl:template match="dlugi_cytat">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+    
+    <xsl:template match="poezja_cyt">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="kwestia">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="didaskalia">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="wywiad_pyt">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="wywiad_odp">
+        <xsl:param name="mixed" />
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <!--
+        ***********************************
+        Style akapitowe oraz strofy i wersy
+        ***********************************
+    -->
+
+    <xsl:template match="akap">
+        <xsl:param name="mixed" />
+        <p x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+    <xsl:template match="akap_cd">
+        <xsl:param name="mixed" />
+        <p x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+    <xsl:template match="akap_dialog">
+        <xsl:param name="mixed" />
+        <p x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+    <!--
+        ********
+        STROFA
+        ********
+    -->
+    <xsl:template match="strofa">
+        <div x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+         
+            <xsl:choose>
+                <xsl:when test="count(br) > 0">
+                    <xsl:variable name="first-verse" select="br[1]/preceding-sibling::node()" />                    
+                    <xsl:call-template name="verse">
+                        <xsl:with-param name="verse-content" select="$first-verse" />                        
+                    </xsl:call-template>
+                    <xsl:for-each select="br">
+                        <xsl:variable name="lnum" select="count(preceding-sibling::br)" />
+                        <!-- select all nodes up to the next br or end of stanza -->
+                        <xsl:variable name="current-verse"
+                            select="following-sibling::node()[count(preceding-sibling::br) = $lnum+1]" />                        
+                        <xsl:call-template name="verse">
+                            <xsl:with-param name="verse-content" select="$current-verse" />                            
+                        </xsl:call-template>
+                    </xsl:for-each>
+                </xsl:when>
+                <xsl:otherwise>
+                    <xsl:call-template name="verse">
+                        <xsl:with-param name="verse-content" select="child::node()" />                        
+                    </xsl:call-template>
+                </xsl:otherwise>
+            </xsl:choose>
+        </div>
+    </xsl:template>
+
+    <xsl:template name="verse">
+        <!-- the verse contents including the last br (if any) -->
+        <xsl:param name="verse-content" />
+        <xsl:variable name="first-tag-name" select="name($verse-content/self::*)" />
+        <!-- name of text nodes is '' == false -->
+
+        <!-- THIS IS A HORROR!!! -->
+        <!-- Possible variants: -->
+        <xsl:choose>
+            <!-- Simple verse == not wers_ tags anywhere until the ending br -->
+            <xsl:when test="not($verse-content[starts-with(name(), 'wers_')])">
+                <p class="wers" x-node="wers">
+                <xsl:apply-templates select="$verse-content[local-name(.) != 'br']">
+                    <xsl:with-param name="mixed" select="true()" />
+                </xsl:apply-templates>
+                </p>
+            </xsl:when>
+
+            <xsl:otherwise>
+            <xsl:apply-templates select="$verse-content[local-name(.) != 'br']">
+                <xsl:with-param name="mixed" select="false()" />
+            </xsl:apply-templates>
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template match="wers_cd|wers_akap|wers_wciety">
+        <xsl:param name="mixed" />
+        <p>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </p>
+    </xsl:template>
+
+    <xsl:template match="br"><xsl:text>/</xsl:text></xsl:template>
+
+
+    <!--
+        *************
+        STYLE ZNAKOWE
+        *************
+    -->
+
+    <!--
+        Tagi obejmujące tytuł dzieła, np. książki, filmu, piosenki,
+        modlitwy, przedstawienia teatr. itd.:
+
+        <tytul_dziela> tytuł-dzieła </tytul_dziela>
+    -->
+    <xsl:template match="tytul_dziela">
+        <xsl:param name="mixed" />
+        <em>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </em>
+    </xsl:template>
+
+    <xsl:template match="wyroznienie|slowo_obce|mat|didask_tekst|osoba|wyp_osoba|www">
+        <xsl:param name="mixed" />
+        <em>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </em>
+    </xsl:template>
+
+    <!--
+        **********
+        SEPARATORY
+        **********
+    -->
+    <xsl:template match="sekcja_swiatlo">
+        <xsl:param name="mixed" />
+        <br><xsl:call-template name="standard-attributes" /></br>
+    </xsl:template>
+
+    <xsl:template match="sekcja_asterysk">
+        <xsl:param name="mixed" />
+        <hr><xsl:call-template name="standard-attributes" /></hr>
+    </xsl:template>
+
+    <xsl:template match="separator_linia">
+        <xsl:param name="mixed" />
+        <hr><xsl:call-template name="standard-attributes" /></hr>
+    </xsl:template>
+
+    <xsl:template match="zastepnik_wersu">
+        <xsl:param name="mixed" />
+        <hr><xsl:call-template name="standard-attributes" /></hr>
+    </xsl:template>
+
+    <!--
+        *************
+           PRZYPISY
+        *************
+    -->
+
+    <!--
+        Przypisy i motywy
+    -->
+    <xsl:template match="pr|pa|pe|pt">       
+        <span x-editable="true">
+            <xsl:call-template name="standard-attributes">
+                <xsl:with-param name="extra-class" select="'annotation-inline-box'" />
+            </xsl:call-template>
+            <a name="anchor-{generate-id(.)}" />
+            <!-- the link to the non-inline version -->
+            <a href="#annotation-{generate-id(.)}" class="annotation"></a>
+            <!-- inline contents -->
+            <span x-annotation-box="true">
+                <xsl:call-template name="context-menu" />
+                <xsl:apply-templates select="node()">
+                    <xsl:with-param name="mixed" select="true()" />
+                </xsl:apply-templates>
+            </span>
+        </span>
+    </xsl:template>
+
+    <xsl:template match="begin">        
+        <span>
+            <xsl:call-template name="standard-attributes" />
+        </span>
+    </xsl:template>
+
+    <xsl:template match="extra|uwaga">
+        <span>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="node()" />
+        </span>
+    </xsl:template>
+
+    <xsl:template match="motyw">
+        <span x-editable="true">
+            <xsl:call-template name="standard-attributes" />
+            <xsl:call-template name="context-menu" />
+            <xsl:value-of select="." />
+        </span>
+    </xsl:template>
+
+    <xsl:template match="end">
+        <span>
+            <xsl:call-template name="standard-attributes" />           
+        </span>
+    </xsl:template>
+
+
+    <!--
+        ****************
+         TEKST WŁAŚCIWY
+        ****************
+    -->
+
+    <xsl:template match="text()">
+        <xsl:param name="mixed" />
+        <xsl:choose>
+            <xsl:when test="normalize-space(.) = ''" />
+            <xsl:when test="not($mixed)"><span x-node="out-of-flow-text" class="out-of-flow-text"
+                    x-content="{.}"></span></xsl:when>
+            <xsl:otherwise><xsl:value-of select="." /></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template match="comment()">
+        <xsl:comment><xsl:value-of select="." /></xsl:comment>
+    </xsl:template>
+
+    <xsl:template match="*[name() != local-name()]">
+        <div>
+            <xsl:call-template name="standard-attributes" />
+            <xsl:apply-templates select="child::node()">
+                <xsl:with-param name="mixed" select="true()" />
+            </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="*">
+        <xsl:message terminate="no">
+        Unmatched tag <xsl:value-of select="name()" />
+        </xsl:message>
+    </xsl:template>
+
+    <xsl:template name="context-menu">
+        <span class="default-menu context-menu">
+            <span class="edit-button">Edit</span>
+        </span>
+        <span class="edit-menu context-menu">
+            <span class="accept-button">OK</span>
+            <span class="reject-button">Cancel</span>
+        </span>
+    </xsl:template>
+
+    <xsl:template name="standard-attributes">
+        <xsl:param name="extra-class" />
+        <xsl:attribute name="class"><xsl:value-of select="local-name()" /><xsl:text>&#x0020;</xsl:text><xsl:value-of select="$extra-class" /></xsl:attribute>
+
+        <!-- we use upper-case attribute names, so we don't have to wory about HTML parsers -->
+        <xsl:attribute name="x-node"><xsl:value-of select="name()" /></xsl:attribute>
+
+        <xsl:if test="local-name() != name()">
+            <xsl:attribute name="x-ns"><xsl:value-of select="namespace-uri()" /></xsl:attribute>
+        </xsl:if>
+
+        <xsl:for-each select="@*">
+            <xsl:variable name="id" select="generate-id()" />
+            <xsl:attribute name="x-attr-value-{$id}"><xsl:value-of select="."/></xsl:attribute>
+            <xsl:attribute name="x-attr-qname-{$id}"><xsl:value-of select="name()"/></xsl:attribute>
+            <xsl:if test="namespace-uri()">
+                <xsl:attribute name="x-attr-ns-{$id}"><xsl:value-of select="namespace-uri()"/></xsl:attribute>
+            </xsl:if>               
+        </xsl:for-each>
+    </xsl:template>
+    
+</xsl:stylesheet>
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index 590825a..597a432
@@ -1,6 +1,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:p="http://platforma.wolnelektury.pl/">
+<html xmlns="http://www.w3.org/1999/xhtml">
     <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
         <title>{% block title %}Platforma Redakcyjna{% block subtitle %}{% endblock subtitle %}{% endblock title%}</title>
@@ -21,9 +21,9 @@
                </span>
         <div id="message-box">{% block message-box %} {% endblock %}</div>
        </div>
-    <div id="content">{% block maincontent %} {% endblock %}</div>
-
+        <div id="content">{% block maincontent %} {% endblock %}</div>
+        </div>
     {% block extrabody %}{% endblock %}
-       </div>
+    http://192.168.56.2:8000/editor/mickiewicz__pan_tadeusz__ksi%C4%99ga_1/
     </body>
 </html>
index 8930c94..2e8a6b4 100755 (executable)
@@ -12,9 +12,8 @@
                 docID: '{{ fileid }}',
                 userID: '{{ euser }}',
                 docURL: '{% url document_view fileid %}{% if euser %}?user={{ euser|urlencode }}{% endif %}',
-                toolbarURL: '{% url toolbar_buttons %}',
-                renderURL: '{% url api.views.render %}',
-                               staticURL: '{{ STATIC_URL }}'
+                toolbarURL: '{% url toolbar_buttons %}',                
+               staticURL: '{{ STATIC_URL }}'
             }          
                 
        </script>
        <script type="text/html" charset="utf-8" id="html-view-template">
                 <div class="htmlview-toolbar">
                     <a class="html-print-link" href="print" ui:baseref="{% url file_print fileid %}" target="_new">{% trans "Print version"  %}</a>
+                    <button class="html-add-motive" type="button">Dodaj motyw</button>
+                    <button class="html-serialize" type="button">Serializuj</button>
                 </div>
                 
                <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">
diff --git a/platforma/templates/renderer.html b/platforma/templates/renderer.html
new file mode 100755 (executable)
index 0000000..84de36d
--- /dev/null
@@ -0,0 +1,153 @@
+{% extends "base.html" %}\r
+\r
+{% block extrahead %}\r
+<link rel="stylesheet" href="{{STATIC_URL}}css/html.css" type="text/css" charset="utf-8" />\r
+<script src="{{STATIC_URL}}js/lib/codemirror/codemirror.js" type="text/javascript" charset="utf-8"></script>\r
+{% endblock %}\r
+\r
+{% block maincontent %}\r
+\r
+<!-- <button type="button" id="render">Render</button>\r
+\r
+<table width="100%" align="center">\r
+    <tr>\r
+        <td width="50%">\r
+                <textarea id="source" cols="70" rows="30" ></textarea>\r
+        </td>\r
+        <td width="50%">\r
+                <textarea id="dest" cols="70" rows="30" ></textarea>\r
+        </td>\r
+    </tr>\r
+</table>\r
+<iframe>\r
+    \r
+</iframe> -->\r
+<div id="target"> </div>\r
+{% endblock %}\r
+\r
+{% block extrabody %}\r
+\r
+<script type="text/javascript">\r
+<![CDATA[\r
+    var editor = new CodeMirror(CodeMirror.replace("target"), {\r
+  parserfile: ["tokenizejavascript.js", "parsejavascript.js"],\r
+  path: "{{STATIC_URL}}js/lib/codemirror",\r
+  stylesheet: "{{STATIC_URL}}css/xmlcolors.css",\r
+  content: "Hello world!"\r
+});\r
+]]>\r
+</script>\r
+\r
+{% comment %}\r
+<script type="text/javascript">\r
+<![CDATA[\r
+    function serializeAttribute(attr, acc) {\r
+        return acc + ' ' + attr.nodeName + '="'+ attr.nodeValue + '"';\r
+    }\r
+\r
+    function serializeElement(element, acc, level)\r
+    {\r
+        var isBlock = false;\r
+\r
+        if(element.nodeName != 'span' && element.nodeName != 'p')\r
+            isBlock = true;\r
+\r
+        if(isBlock) {\r
+            for(var i=0; i < level; i++)\r
+                acc += '  ';\r
+        }\r
+        \r
+        acc += "<" + element.nodeName;\r
+        \r
+        for(var i=0; i < element.attributes.length; i++)\r
+            acc = serializeAttribute(element.attributes.item(i), acc);\r
+\r
+        if(element.firstChild)\r
+        {\r
+            acc += ">\n";\r
+\r
+            if(element.firstChild)\r
+                acc = serializeNode(element.firstChild, acc, level+1);\r
+\r
+            acc += "\n";\r
+            \r
+            for(var i=0; i < level; i++)\r
+                acc += '  ';\r
+\r
+            acc += "</"+element.nodeName + ">";            \r
+        }\r
+        else {\r
+            acc += " />";\r
+        }\r
+\r
+        if(isBlock) acc += "\n";\r
+        \r
+        return acc;\r
+    }\r
+\r
+\r
+    // step-by-step serializer\r
+    function serializeNode(node, acc, level)\r
+    {\r
+        \r
+\r
+        if(node.nodeType == 11)\r
+            return serializeNode(node.firstChild, acc, level);\r
+\r
+        if(node.nodeType == 1)\r
+            acc = serializeElement(node, acc, level);\r
+        \r
+        else if(node.nodeType == 3)\r
+            acc += node.nodeValue;\r
+\r
+        if(node.nextSibling)\r
+            return serializeNode(node.nextSibling, acc, level);\r
+        else\r
+            return acc;\r
+    }\r
+\r
+    function serializeXML(element) {\r
+        return serializeNode(element, '', 0);\r
+    }\r
+\r
+    // w3c version first\r
+    var there = new XSLTProcessor();\r
+    var here = new XSLTProcessor();\r
+\r
+    $.ajax({\r
+        url: "/static/xsl/wl2html_client.xsl",\r
+        dataType: 'xml',\r
+        success: function(data) {\r
+            there.importStylesheet(data);\r
+            console.log('There XSL loaded successfully');\r
+        },\r
+        async: false\r
+    });\r
+\r
+    $.ajax({\r
+        url: "/static/xsl/html2wl_client.xsl",\r
+        dataType: 'xml',\r
+        success: function(data) {\r
+            here.importStylesheet(data);\r
+            console.log('Here XSL loaded successfully');\r
+        },\r
+        async: false\r
+    });\r
+    \r
+    $('#render').click(function()\r
+    {\r
+        src = $('#source').val();\r
+        src = src.replace(/\/\s+/g, '<br />');\r
+        var doc = (new DOMParser()).parseFromString(src, "text/xml");\r
+        // console.log("Parsed", doc);\r
+        var along = there.transformToDocument(doc).documentElement;\r
+        // console.log("HTML", along, serializeXML(along) );\r
+        var xfrm = here.transformToDocument(along).documentElement;\r
+        // console.log("WLML", xfrm, serializeXML(xfrm) );\r
+        var out = (new XMLSerializer()).serializeToString(xfrm);\r
+        $('#dest').val(out);\r
+    });\r
+]]>\r
+</script>\r
+{% endcomment %}\r
+{% endblock %}
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index 498b5b2..1f7372a
@@ -13,6 +13,8 @@ urlpatterns = patterns('',
     url(r'^$', 'explorer.views.file_list', name='file_list'),        
     url(r'^file/upload', 'explorer.views.file_upload', name='file_upload'),
 
+    url(r'^renderer$', 'explorer.views.renderer_test'),
+
     url(r'^management/pull-requests$', 'explorer.views.pull_requests'),
   
     # Editor panels
@@ -26,6 +28,8 @@ urlpatterns = patterns('',
     url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
     url(r'^admin/(.*)', admin.site.root),
 
+
+
     # Our über-restful api
     url(r'^api/', include('api.urls')),