xml format change + fixes
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 16 Dec 2011 14:43:38 +0000 (15:43 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 16 Dec 2011 14:43:38 +0000 (15:43 +0100)
14 files changed:
apps/catalogue/models/listeners.py
apps/wiki_img/templates/wiki_img/document_details.html
apps/wiki_img/templates/wiki_img/save_dialog.html [deleted file]
apps/wiki_img/templates/wiki_img/tag_dialog.html [deleted file]
apps/wiki_img/urls.py
apps/wiki_img/views.py
redakcja/settings/compress.py
redakcja/static/js/wiki_img/dialog_addtag.js [deleted file]
redakcja/static/js/wiki_img/dialog_save.js [deleted file]
redakcja/static/js/wiki_img/loader_readonly.js
redakcja/static/js/wiki_img/toolbar.js [deleted file]
redakcja/static/js/wiki_img/view_editor_source.js [deleted file]
redakcja/static/js/wiki_img/view_summary.js [deleted file]
redakcja/static/js/wiki_img/wikiapi.js

index de1387e..4e76b0d 100755 (executable)
@@ -39,16 +39,25 @@ models.signals.post_save.connect(user_changed, sender=User)
 
 
 def publish_listener(sender, *args, **kwargs):
-    sender.book.touch()
-    for c in sender.book:
+    sender.touch()
+    for c in sender:
         c.touch()
-post_publish.connect(publish_listener)
+post_publish.connect(publish_listener, sender=Book)
 
+def publish_listener(sender, *args, **kwargs):
+    sender.touch()
+post_publish.connect(publish_listener, sender=Image)
+
+
+def chunk_publishable_listener(sender, *args, **kwargs):
+    sender.tree.touch()
+    if isinstance(sender.tree, Chunk):
+        sender.tree.book.touch()
+post_publishable.connect(chunk_publishable_listener)
 
 def publishable_listener(sender, *args, **kwargs):
     sender.tree.touch()
-    sender.tree.book.touch()
-post_publishable.connect(publishable_listener)
+post_publishable.connect(publishable_listener, sender=Image)
 
 
 def listener_create(sender, instance, created, **kwargs):
index fc2e207..0dfc9ae 100644 (file)
 {% endblock %}
 
 {% block dialogs %}
-    {% include "wiki_img/save_dialog.html" %}
+    {% include "wiki/save_dialog.html" %}
+    {% include "wiki/revert_dialog.html" %}
+    {% if can_pubmark %}
+        {% include "wiki/pubmark_dialog.html" %}
+    {% endif %}
 {% endblock %}
 
 {% block editor-class %}
diff --git a/apps/wiki_img/templates/wiki_img/save_dialog.html b/apps/wiki_img/templates/wiki_img/save_dialog.html
deleted file mode 100644 (file)
index e8f89e6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{% load i18n %}
-<div id="save_dialog" class="dialog" data-ui-jsclass="SaveDialog">
-       <form method="POST" action="">
-    {% csrf_token %}
-       <p>{{ forms.text_save.comment.label }}</p>
-       <p class="help_text">
-               {{ forms.text_save.comment.help_text}}
-               <span data-ui-error-for="{{ forms.text_save.comment.name }}"> </span>
-       </p>
-       {{forms.text_save.comment }}
-
-
-
-       {% for f in forms.text_save.hidden_fields %}
-               {{ f }}
-       {% endfor %}
-
-       <p data-ui-error-for="__all__"> </p>
-
-       <p class="action_area">
-               <button type="submit" class"ok" data-ui-action="save">Zapisz</button>
-               <button type="button" class="cancel" data-ui-action="cancel">Anuluj</button>
-       </p>
-       </form>
-</div>
diff --git a/apps/wiki_img/templates/wiki_img/tag_dialog.html b/apps/wiki_img/templates/wiki_img/tag_dialog.html
deleted file mode 100644 (file)
index bc601cb..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{% load i18n %}
-<div id="add_tag_dialog" class="dialog" data-ui-jsclass="AddTagDialog">
-       <form method="POST" action="#">
-               {% for field in forms.add_tag.visible_fields %}
-               <p>{{ field.label_tag }} {{ field }} <span data-ui-error-for="{{ field.name }}"> </span></p>
-               <p>{{ field.help_text }}</p>
-               {% endfor %}
-
-               {% for f in forms.add_tag.hidden_fields %}
-                       {{ f }}
-               {% endfor %}
-               <p data-ui-error-for="__all__"> </p>
-
-               <p class="action_area">
-                       <button type="submit" class"ok" data-ui-action="save">{% trans "Save" %}</button>
-                       <button type="button" class="cancel" data-ui-action="cancel">{% trans "Cancel" %}</button>
-               </p>
-       </form>
-</div>
index b4396c6..518da6b 100644 (file)
@@ -12,7 +12,13 @@ urlpatterns = patterns('wiki_img.views',
     url(r'^text/(?P<image_id>\d+)/$',
         'text', name="wiki_img_text"),
 
-    url(r'^history/(?P<chunk_id>\d+)/$',
-        'history', name="wiki_history"),
+    url(r'^history/(?P<object_id>\d+)/$',
+        'history', name="wiki_img_history"),
+
+    url(r'^revert/(?P<object_id>\d+)/$',
+        'revert', name='wiki_img_revert'),
+
+    url(r'^diff/(?P<object_id>\d+)/$', 'diff', name="wiki_img_diff"),
+    url(r'^pubmark/(?P<object_id>\d+)/$', 'pubmark', name="wiki_img_pubmark"),
 
 )
index 9e87f66..2b987dc 100644 (file)
@@ -5,15 +5,20 @@ logger = logging.getLogger("fnp.wiki_img")
 
 from django.views.generic.simple import direct_to_template
 from django.core.urlresolvers import reverse
-from wiki.helpers import JSONResponse
+from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError,
+                ajax_require_permission)
+
 from django import http
 from django.shortcuts import get_object_or_404
-from django.views.decorators.http import require_GET
+from django.views.decorators.http import require_GET, require_POST
 from django.conf import settings
 from django.utils.formats import localize
+from django.utils.translation import ugettext as _
 
 from catalogue.models import Image
-from wiki_img.forms import DocumentTextSaveForm
+from wiki import forms
+from wiki import nice_diff
+from wiki_img.forms import ImageSaveForm
 
 #
 # Quick hack around caching problems, TODO: use ETags
@@ -28,8 +33,11 @@ def editor(request, slug, template_name='wiki_img/document_details.html'):
     return direct_to_template(request, template_name, extra_context={
         'document': doc,
         'forms': {
-            "text_save": DocumentTextSaveForm(user=request.user, prefix="textsave"),
+            "text_save": ImageSaveForm(user=request.user, prefix="textsave"),
+            "text_revert": forms.DocumentTextRevertForm(prefix="textrevert"),
+            "pubmark": forms.DocumentPubmarkForm(prefix="pubmark"),
         },
+        'can_pubmark': request.user.has_perm('catalogue.can_pubmark_image'),
         'REDMINE_URL': settings.REDMINE_URL,
     })
 
@@ -42,8 +50,6 @@ def editor_readonly(request, slug, template_name='wiki_img/document_details_read
     except (KeyError):
         raise Http404
 
-
-
     return direct_to_template(request, template_name, extra_context={
         'document': doc,
         'revision': revision,
@@ -56,7 +62,7 @@ def editor_readonly(request, slug, template_name='wiki_img/document_details_read
 def text(request, image_id):
     doc = get_object_or_404(Image, pk=image_id)
     if request.method == 'POST':
-        form = DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave")
+        form = ImageSaveForm(request.POST, user=request.user, prefix="textsave")
         if form.is_valid():
             if request.user.is_authenticated():
                 author = request.user
@@ -71,16 +77,16 @@ def text(request, image_id):
             stage = form.cleaned_data['stage_completed']
             tags = [stage] if stage else []
             publishable = (form.cleaned_data['publishable'] and
-                    request.user.has_perm('catalogue.can_pubmark'))
+                    request.user.has_perm('catalogue.can_pubmark_image'))
             doc.commit(author=author,
-                       text=text,
-                       parent=parent,
-                       description=form.cleaned_data['comment'],
-                       tags=tags,
-                       author_name=form.cleaned_data['author_name'],
-                       author_email=form.cleaned_data['author_email'],
-                       publishable=publishable,
-                       )
+                   text=text,
+                   parent=parent,
+                   description=form.cleaned_data['comment'],
+                   tags=tags,
+                   author_name=form.cleaned_data['author_name'],
+                   author_email=form.cleaned_data['author_email'],
+                   publishable=publishable,
+                )
             revision = doc.revision()
             return JSONResponse({
                 'text': doc.materialize() if parent_revision != revision else None,
@@ -110,9 +116,9 @@ def text(request, image_id):
 
 
 @never_cache
-def history(request, chunk_id):
+def history(request, object_id):
     # TODO: pagination
-    doc = get_object_or_404(Image, pk=chunk_id)
+    doc = get_object_or_404(Image, pk=object_id)
     if not doc.accessible(request):
         return HttpResponseForbidden("Not authorized.")
 
@@ -127,3 +133,82 @@ def history(request, chunk_id):
                 "tag": ',\n'.join(unicode(tag) for tag in change.tags.all()),
             })
     return JSONResponse(changes)
+
+
+@never_cache
+@require_POST
+def revert(request, object_id):
+    form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
+    if form.is_valid():
+        doc = get_object_or_404(Image, pk=object_id)
+        if not doc.accessible(request):
+            return HttpResponseForbidden("Not authorized.")
+
+        revision = form.cleaned_data['revision']
+
+        comment = form.cleaned_data['comment']
+        comment += "\n#revert to %s" % revision
+
+        if request.user.is_authenticated():
+            author = request.user
+        else:
+            author = None
+
+        before = doc.revision()
+        logger.info("Reverting %s to %s", object_id, revision)
+        doc.at_revision(revision).revert(author=author, description=comment)
+
+        return JSONResponse({
+            'text': doc.materialize() if before != doc.revision() else None,
+            'meta': {},
+            'revision': doc.revision(),
+        })
+    else:
+        return JSONFormInvalid(form)
+
+
+@never_cache
+def diff(request, object_id):
+    revA = int(request.GET.get('from', 0))
+    revB = int(request.GET.get('to', 0))
+
+    if revA > revB:
+        revA, revB = revB, revA
+
+    if revB == 0:
+        revB = None
+
+    doc = get_object_or_404(Image, pk=object_id)
+    if not doc.accessible(request):
+        return HttpResponseForbidden("Not authorized.")
+
+    # allow diff from the beginning
+    if revA:
+        docA = doc.at_revision(revA).materialize()
+    else:
+        docA = ""
+    docB = doc.at_revision(revB).materialize()
+
+    return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(),
+                                         docB.splitlines(), context=3))
+
+
+@require_POST
+@ajax_require_permission('catalogue.can_pubmark_image')
+def pubmark(request, object_id):
+    form = forms.DocumentPubmarkForm(request.POST, prefix="pubmark")
+    if form.is_valid():
+        doc = get_object_or_404(Image, pk=object_id)
+        if not doc.accessible(request):
+            return HttpResponseForbidden("Not authorized.")
+
+        revision = form.cleaned_data['revision']
+        publishable = form.cleaned_data['publishable']
+        change = doc.at_revision(revision)
+        if publishable != change.publishable:
+            change.set_publishable(publishable)
+            return JSONResponse({"message": _("Revision marked")})
+        else:
+            return JSONResponse({"message": _("Nothing changed")})
+    else:
+        return JSONFormInvalid(form)
index 34cfa2f..ddd0aec 100644 (file)
@@ -75,18 +75,19 @@ COMPRESS_JS = {
 
                 # base UI
                 'js/wiki_img/base.js',
-                'js/wiki_img/toolbar.js',
+                'js/wiki/toolbar.js',
 
                 # dialogs
-                'js/wiki_img/dialog_save.js',
-                'js/wiki_img/dialog_addtag.js',
+                'js/wiki/dialog_save.js',
+                'js/wiki/dialog_revert.js',
+                'js/wiki/dialog_pubmark.js',
 
                 # views
-                'js/wiki_img/view_summary.js',
                 'js/wiki_img/view_editor_objects.js',
                 'js/wiki_img/view_editor_motifs.js',
                 'js/wiki/view_editor_source.js',
                 'js/wiki/view_history.js',
+                'js/wiki/view_column_diff.js',
         ),
         'output_filename': 'compressed/detail_img_scripts_?.js',
      },
diff --git a/redakcja/static/js/wiki_img/dialog_addtag.js b/redakcja/static/js/wiki_img/dialog_addtag.js
deleted file mode 100644 (file)
index 1a90ccf..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Dialog for saving document to the server
- *
- */
-(function($){
-
-    function AddTagDialog(element, options){
-        if (!options.revision  && options.revision != 0)
-            throw "AddTagDialog needs a revision number.";
-
-        this.ctx = $.wiki.exitContext();
-        this.clearForm();
-
-        /* fill out hidden fields */
-        this.$form = $('form', element);
-
-        $("input[name='addtag-id']", this.$form).val(CurrentDocument.id);
-        $("input[name='addtag-revision']", this.$form).val(options.revision);
-
-        $.wiki.cls.GenericDialog.call(this, element);
-    };
-
-    AddTagDialog.prototype = $.extend(new $.wiki.cls.GenericDialog(), {
-        cancelAction: function(){
-            $.wiki.enterContext(this.ctx);
-            this.hide();
-        },
-
-        saveAction: function(){
-            var self = this;
-
-            self.$elem.block({
-                message: "Dodawanie tagu",
-                fadeIn: 0,
-            });
-
-            CurrentDocument.setTag({
-                form: self.$form,
-                success: function(doc, changed, info){
-                    self.$elem.block({
-                        message: info,
-                        timeout: 2000,
-                        fadeOut: 0,
-                        onUnblock: function(){
-                            self.hide();
-                            $.wiki.enterContext(self.ctx);
-                        }
-                    });
-                },
-                failure: function(doc, info){
-                    console.log("Failure", info);
-                    self.reportErrors(info);
-                    self.$elem.unblock();
-                }
-            });
-        }
-    });
-
-    /* make it global */
-    $.wiki.cls.AddTagDialog = AddTagDialog;
-})(jQuery);
diff --git a/redakcja/static/js/wiki_img/dialog_save.js b/redakcja/static/js/wiki_img/dialog_save.js
deleted file mode 100644 (file)
index 84f012c..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Dialog for saving document to the server
- *
- */
-(function($) {
-
-       function SaveDialog(element) {
-               this.ctx = $.wiki.exitContext();
-               this.clearForm();
-
-               /* fill out hidden fields */
-               this.$form = $('form', element);
-
-               $("input[name='textsave-id']", this.$form).val(CurrentDocument.id);
-               $("input[name='textsave-parent_commit']", this.$form).val(CurrentDocument.commit);
-
-               $.wiki.cls.GenericDialog.call(this, element);
-       };
-
-       SaveDialog.prototype = new $.wiki.cls.GenericDialog();
-
-       SaveDialog.prototype.cancelAction = function() {
-               $.wiki.enterContext(this.ctx);
-               this.hide();
-       };
-
-       SaveDialog.prototype.saveAction = function() {
-                       var self = this;
-
-                       self.$elem.block({
-                               message: "Zapisywanie... <br/><button id='save-hide'>ukryj</button>",
-                               fadeIn: 0,
-                       });
-            $.wiki.blocking = self.$elem;
-
-                       try {
-
-                               CurrentDocument.save({
-                                       form: self.$form,
-                                       success: function(doc, changed, info){
-                                               self.$elem.block({
-                                                       message: info,
-                                                       timeout: 2000,
-                                                       fadeOut: 0,
-                                                       onUnblock: function() {
-                                                               self.hide();
-                                                               $.wiki.enterContext(self.ctx);
-                                                       }
-                                               });
-                                       },
-                                       failure: function(doc, info) {
-                                               console.log("Failure", info);
-                                               self.reportErrors(info);
-                                               self.$elem.unblock();
-                                       }
-                               });
-                       } catch(e) {
-                               console.log('Exception:', e)
-                               self.$elem.unblock();
-                       }
-       }; /* end of save dialog */
-
-       /* make it global */
-       $.wiki.cls.SaveDialog = SaveDialog;
-})(jQuery);
index 1ce15b7..b2f574d 100755 (executable)
@@ -8,6 +8,7 @@ if (!window.console) {
 
 DEFAULT_PERSPECTIVE = "#MotifsPerspective";
 
+
 $(function()
 {
        var tabs = $('ol#tabs li');
@@ -37,10 +38,11 @@ $(function()
                        p.destroy();
                        return false;
         });
-
+/*
         $(window).resize(function(){
             $('iframe').height($(window).height() - $('#tabs').outerHeight() - $('#source-editor .toolbar').outerHeight());
         });
+        */
 
                $(document).bind('wlapi_document_changed', function(event, doc) {
                        try {
@@ -56,8 +58,6 @@ $(function()
                                $('#loading-overlay').fadeOut();
                                var active_tab = document.location.hash || DEFAULT_PERSPECTIVE;
 
-                               $(window).resize();
-
                                console.log("Initial tab is:", active_tab)
                                $.wiki.switchToTab(active_tab);
                        },
diff --git a/redakcja/static/js/wiki_img/toolbar.js b/redakcja/static/js/wiki_img/toolbar.js
deleted file mode 100644 (file)
index 3eafdae..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Toolbar plugin.
- */
-(function($) {
-
-    $.fn.toolbarize = function(options) {
-        var $toolbar = $(this);
-        var $container = $('.button_group_container', $toolbar);
-
-        $('.button_group button', $toolbar).click(function(event){
-            event.preventDefault();
-
-            var params = eval("(" + $(this).attr('data-ui-action-params') + ")");
-
-            scriptletCenter.callInteractive({
-                action: $(this).attr('data-ui-action'),
-                context: options.actionContext,
-                extra: params
-            });
-        });
-
-        $toolbar.children().filter('select').change(function(event){
-            var slug = $(this).val();
-            $container.scrollLeft(0);
-            $('*[data-group]').hide().filter('[data-group=' + slug + ']').show();
-        }).change();
-
-        $('button.next', $toolbar).click(function() {
-            var $current_group = $('.button_group:visible', $toolbar);
-            var scroll = $container.scrollLeft();
-
-            var $hidden = $("li", $current_group).filter(function() {
-                return ($(this).position().left + $(this).outerWidth()) > $container.width();
-            }).first();
-
-            if($hidden.length > 0) {
-                scroll = $hidden.position().left + scroll + $hidden.outerWidth() - $container.width() + 1;
-                $container.scrollLeft(scroll);
-            };
-        });
-
-        $('button.prev', $toolbar).click(function() {
-            var $current_group = $('.button_group:visible', $toolbar);
-            var scroll = $container.scrollLeft();
-
-            /* first not visible element is: */
-            var $hidden = $("li", $current_group).filter(function() {
-                return $(this).position().left < 0;
-            }).last();
-
-            if( $hidden.length > 0)
-            {
-                scroll = scroll + $hidden.position().left;
-                $container.scrollLeft(scroll);
-            };
-        });
-
-    };
-
-})(jQuery);
\ No newline at end of file
diff --git a/redakcja/static/js/wiki_img/view_editor_source.js b/redakcja/static/js/wiki_img/view_editor_source.js
deleted file mode 100644 (file)
index 8fb9358..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* COMMENT */
-(function($) {
-
-       function CodeMirrorPerspective(options)
-       {
-               var old_callback = options.callback;
-        options.callback = function(){
-                       var self = this;
-
-                       this.codemirror = CodeMirror.fromTextArea('codemirror_placeholder', {
-                               parserfile: 'parsexml.js',
-                               path: STATIC_URL + "js/lib/codemirror-0.8/",
-                               stylesheet: STATIC_URL + "css/xmlcolors_20100906.css",
-                               parserConfig: {
-                                       useHTMLKludges: false
-                               },
-                               iframeClass: 'xml-iframe',
-                               textWrapping: true,
-                               lineNumbers: true,
-                               width: "100%",
-                               height: "100%",
-                               tabMode: 'spaces',
-                               indentUnit: 0,
-                               readOnly: CurrentDocument.readonly || false,
-                               initCallback: function(){
-
-                                       self.codemirror.grabKeys(function(event) {
-                                               if (event.button) {
-                                                       $(event.button).trigger('click');
-                                                       event.button = null;
-                                               }
-                                       }, function(keycode, event) {
-                                               if(!event.altKey)
-                                                       return false;
-
-                                               var c = String.fromCharCode(keycode).toLowerCase();
-                                               var button = $("#source-editor button[data-ui-accesskey='"+c+"']");
-                                               if(button.length == 0)
-                                                       return false;
-
-                                               /* it doesn't matter which button we pick - all do the same */
-                                               event.button = button[0];
-                                               return true;
-                                       });
-
-                                       $('#source-editor .toolbar').toolbarize({
-                                           actionContext: self.codemirror
-                                       });
-
-                                       console.log("Initialized CodeMirror");
-
-                                       // textarea is no longer needed
-                                       $('codemirror_placeholder').remove();
-
-                                       old_callback.call(self);
-                               }
-                       });
-               };
-
-               $.wiki.Perspective.call(this, options);
-       };
-
-
-       CodeMirrorPerspective.prototype = new $.wiki.Perspective();
-
-       CodeMirrorPerspective.prototype.freezeState = function() {
-               this.config().position = this.codemirror.win.scrollY || 0;
-       };
-
-       CodeMirrorPerspective.prototype.unfreezeState = function () {
-               this.codemirror.win.scroll(0, this.config().position || 0);
-       };
-
-       CodeMirrorPerspective.prototype.onEnter = function(success, failure) {
-               $.wiki.Perspective.prototype.onEnter.call(this);
-
-               console.log('Entering', this.doc);
-               this.codemirror.setCode(this.doc.text);
-
-               /* fix line numbers bar */
-               var $nums = $('.CodeMirror-line-numbers');
-           var barWidth = $nums.width();
-
-               $(this.codemirror.frame.contentDocument.body).css('padding-left', barWidth);
-               // $nums.css('left', -barWidth);
-
-               $(window).resize();
-               this.unfreezeState(this._uistate);
-
-               if(success) success();
-       }
-
-       CodeMirrorPerspective.prototype.onExit = function(success, failure) {
-               this.freezeState();
-
-               $.wiki.Perspective.prototype.onExit.call(this);
-               console.log('Exiting', this.doc);
-               this.doc.setText(this.codemirror.getCode());
-
-        if ($('.vsplitbar').hasClass('active') && $('#SearchPerspective').hasClass('active')) {
-            $.wiki.switchToTab('#ScanGalleryPerspective');
-        }
-
-               if(success) success();
-       }
-
-       $.wiki.CodeMirrorPerspective = CodeMirrorPerspective;
-
-})(jQuery);
diff --git a/redakcja/static/js/wiki_img/view_summary.js b/redakcja/static/js/wiki_img/view_summary.js
deleted file mode 100644 (file)
index 5d06647..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-(function($){
-
-       function SummaryPerspective(options) {
-               var old_callback = options.callback;
-               var self = this;
-
-               $.wiki.Perspective.call(this, options);
-    };
-
-    SummaryPerspective.prototype = new $.wiki.Perspective();
-
-    SummaryPerspective.prototype.freezeState = function(){
-        // must
-    };
-
-       SummaryPerspective.prototype.onEnter = function(success, failure){
-               $.wiki.Perspective.prototype.onEnter.call(this);
-
-               console.log("Entered summery view");
-       };
-
-       $.wiki.SummaryPerspective = SummaryPerspective;
-
-})(jQuery);
-
index 0f56ffe..33af176 100644 (file)
                        return base_path + "/text/" + arguments[1] + "/";
                }
 
-               if (vname == "ajax_document_history") {
+        if (vname == "ajax_document_revert") {
+            return base_path + "/revert/" + arguments[1] + '/';
+        }
 
-                       return base_path + "/history/" + arguments[1] + "/";
+               if (vname == "ajax_document_history") {
+                       return base_path + "/history/" + arguments[1] + '/';
                }
-*/
-/*
-               if (vname == "ajax_document_diff")
-                       return base_path + "/" + arguments[1] + "/diff";
 
-        if (vname == "ajax_document_rev")
-            return base_path + "/" + arguments[1] + "/rev";
-
-               if (vname == "ajax_document_addtag")
-                       return base_path + "/" + arguments[1] + "/tags";
+               if (vname == "ajax_document_diff")
+                       return base_path + "/diff/" + arguments[1] + '/';
 
-               if (vname == "ajax_publish")
-                       return base_path + "/" + arguments[1] + "/publish";*/
+               if (vname == "ajax_document_pubmark")
+                       return base_path + "/pubmark/" + arguments[1] + '/';
 
                console.log("Couldn't reverse match:", vname);
                return "/404.html";
                        }
                });
        };
+       WikiDocument.prototype.fetchDiff = function(params) {
+               /* this doesn't modify anything, so no locks */
+               var self = this;
+               params = $.extend({
+                       'from': self.revision,
+                       'to': self.revision
+               }, noops, params);
+               $.ajax({
+                       method: "GET",
+                       url: reverse("ajax_document_diff", self.id),
+                       dataType: 'html',
+                       data: {
+                               "from": params['from'],
+                               "to": params['to']
+                       },
+                       success: function(data) {
+                               params['success'](self, data);
+                       },
+                       error: function() {
+                               params['failure'](self, "Nie udało się wczytać porównania wersji.");
+                       }
+               });
+       };
 
        /*
         * Set document's text
         });
        }; /* end of save() */
 
-       WikiDocument.prototype.publish = function(params) {
-               params = $.extend({}, noops, params);
-               var self = this;
-               $.ajax({
-                       url: reverse("ajax_publish", self.id),
-                       type: "POST",
-                       dataType: "json",
-                       success: function(data) {
-                               params.success(self, data);
-                       },
-                       error: function(xhr) {
-                               if (xhr.status == 403 || xhr.status == 401) {
-                                       params.failure(self, "Nie masz uprawnień lub nie jesteś zalogowany.");
-                               }
-                               else {
-                                       try {
-                                               params.failure(self, xhr.responseText);
-                                       }
-                                       catch (e) {
-                                               params.failure(self, "Nie udało się - błąd serwera.");
-                                       };
-                               };
+    WikiDocument.prototype.revertToVersion = function(params) {
+        var self = this;
+        params = $.extend({}, noops, params);
 
-                       }
-               });
-       };
-       WikiDocument.prototype.setTag = function(params) {
+        if (params.revision >= this.revision) {
+            params.failure(self, 'Proszę wybrać rewizję starszą niż aktualna.');
+            return;
+        }
+
+        // Serialize form to dictionary
+        var data = {};
+        $.each(params['form'].serializeArray(), function() {
+            data[this.name] = this.value;
+        });
+
+        $.ajax({
+            url: reverse("ajax_document_revert", self.id),
+            type: "POST",
+            dataType: "json",
+            data: data,
+            success: function(data) {
+                if (data.text) {
+                    self.text = data.text;
+                    self.revision = data.revision;
+                    self.gallery = data.gallery;
+                    self.triggerDocumentChanged();
+
+                    params.success(self, "Udało się przywrócić wersję :)");
+                }
+                else {
+                    params.failure(self, "Przywracana wersja identyczna z aktualną. Anulowano przywracanie.");
+                }
+            },
+            error: function(xhr) {
+                params.failure(self, "Nie udało się przywrócić wersji - błąd serwera.");
+            }
+        });
+    };
+
+       WikiDocument.prototype.pubmark = function(params) {
                params = $.extend({}, noops, params);
                var self = this;
                var data = {
-                       "addtag-id": self.id,
+                       "pubmark-id": self.id,
                };
 
                /* unpack form */
                });
 
                $.ajax({
-                       url: reverse("ajax_document_addtag", self.id),
+                       url: reverse("ajax_document_pubmark", self.id),
                        type: "POST",
                        dataType: "json",
                        data: data,
                });
        };
 
+
+
     WikiDocument.prototype.getImageItems = function(tag) {
         var self = this;
 
         }
 
         var a = [];
-        $(tag, doc).each(function(i, e) {
+        $('sem[type="'+tag+'"]', doc).each(function(i, e) {
             var $e = $(e);
-            a.push([
-                $e.text(),
-                $e.attr('x1'),
-                $e.attr('y1'),
-                $e.attr('x2'),
-                $e.attr('y2')
-            ]);
+            var $div = $e.children().first()
+            var value = $e.attr(tag);
+            $e.find('div').each(function(i, div) {
+                var $div = $(div);
+                switch ($div.attr('type')) {
+                    case 'area':
+                        a.push([
+                            value,
+                            $div.attr('x1'),
+                            $div.attr('y1'),
+                            $div.attr('x2'),
+                            $div.attr('y2')
+                        ]);
+                        break;
+                    case 'whole':
+                        a.push([
+                            value,
+                            null, null, null, null
+                        ]);
+                        break
+                }
+            });
         });
 
         return a;
             return null;
         }
 
-        $(tag, doc).remove();
+        $('sem[type="'+tag+'"]', doc).remove();
         $root = $(doc.firstChild);
         $.each(items, function(i, e) {
-            var el = $(doc.createElement(tag));
-            el.text(e[0]);
-            if (e[1] !== null) {
-                el.attr('x1', e[1]);
-                el.attr('y1', e[2]);
-                el.attr('x2', e[3]);
-                el.attr('y2', e[4]);
+            var $sem = $(doc.createElement("sem"));
+            $sem.attr('type', tag);
+            $sem.attr(tag, e[0]);
+            $div = $(doc.createElement("div"));
+            if (e[1]) {
+                $div.attr('type', 'area');
+                $div.attr('x1', e[1]);
+                $div.attr('y1', e[2]);
+                $div.attr('x2', e[3]);
+                $div.attr('y2', e[4]);
+            }
+            else {
+                $div.attr('type', 'whole');
             }
-            $root.append(el);
+            $sem.append($div);
+            $root.append($sem);
         });
-        self.setText(serializer.serializeToString(doc));
+        self.setText(XML(serializer.serializeToString(doc)).toXMLString());
     }