Allow assigning woblink authors in catalogue.
[redakcja.git] / src / redakcja / static / js / wiki / view_editor_wysiwyg.js
index 3ec4f70..bd67db6 100644 (file)
@@ -1,4 +1,4 @@
-(function($){
+(function($) {
 
     /* Show theme to the user */
     function selectTheme(themeId){
@@ -6,8 +6,8 @@
         selection.removeAllRanges();
 
         var range = document.createRange();
-        var s = $(".motyw[theme-class='" + themeId + "']")[0];
-        var e = $(".end[theme-class='" + themeId + "']")[0];
+        var s = $("[x-node='motyw'][theme-class='" + themeId + "']")[0];
+        var e = $("[x-node='end'][theme-class='" + themeId + "']")[0];
 
         if (s && e) {
             range.setStartAfter(s);
 
     /* Verify insertion port for annotation or theme */
     function verifyTagInsertPoint(node){
-        if (node.nodeType == 3) { // Text Node
+        if (node.nodeType == Node.TEXT_NODE) {
             node = node.parentNode;
         }
 
-        if (node.nodeType != 1) {
+        if (node.nodeType != Node.ELEMENT_NODE) {
             return false;
         }
 
         node = $(node);
+        if (node.attr('id') == 'caret') {
+            node = node.parent();
+        }
+        while (node.attr('x-pass-thru')) {
+            node = node.parent();
+        }
         var xtype = node.attr('x-node');
 
         if (!xtype || (xtype.search(':') >= 0) ||
             return false;
         }
 
+        return true;
+    }
+
+    function verifyThemeBoundaryPoint(node) {
+        if (!verifyTagInsertPoint(node)) return false;
+        node = $(node);
         // don't allow themes inside annotations
         if (node.closest('[x-node="pe"]').length > 0)
             return false;
         var text = "";
 
         $(fragment.childNodes).each(function(){
-            if (this.nodeType == 3) // textNode
+            if (this.nodeType == Node.TEXT_NODE)
                 text += this.nodeValue;
             else {
-                if (this.nodeType == 1 &&
+                if (this.nodeType == Node.ELEMENT_NODE &&
                         $.inArray($(this).attr('x-node'), ANNOT_FORBIDDEN) == -1) {
                     text += html2plainText(this);
                 }
         var selection = window.getSelection();
         var n = selection.rangeCount;
 
-        if (n == 0) {
+        if (selection.isCollapsed) {
             window.alert("Nie zaznaczono żadnego obszaru");
             return false;
         }
 
-        // for now allow only 1 range
-        if (n > 1) {
-            window.alert("Zaznacz jeden obszar");
-            return false;
-        }
-
-        // remember the selected range
-        var range = selection.getRangeAt(0);
+        var range = selection.getRangeAt(n - 1);
 
         if (!verifyTagInsertPoint(range.endContainer)) {
             window.alert("Nie można wstawić w to miejsce przypisu.");
             return false;
         }
 
-        // BUG #273 - selected text can contain themes, which should be omitted from
-        // defining term
-        var text = html2plainText(range.cloneContents());
+        text = '';
+        for (let i = 0; i < n; ++ i) {
+            let rangeI = selection.getRangeAt(i);
+            if (verifyTagInsertPoint(rangeI.startContainer) &&
+                verifyTagInsertPoint(rangeI.endContainer)) {
+                text += html2plainText(rangeI.cloneContents());
+            }
+        }
         var tag = $('<span></span>');
         range.collapse(false);
         range.insertNode(tag[0]);
     }
 
 
+
+
+
+
     /* Insert theme using current selection */
 
     function addTheme(){
         // verify if the start/end points make even sense -
         // they must be inside a x-node (otherwise they will be discarded)
         // and the x-node must be a main text
-        if (!verifyTagInsertPoint(range.startContainer)) {
+        if (!verifyThemeBoundaryPoint(range.startContainer)) {
             window.alert("Motyw nie może się zaczynać w tym miejscu.");
             return false;
         }
 
-        if (!verifyTagInsertPoint(range.endContainer)) {
+        if (!verifyThemeBoundaryPoint(range.endContainer)) {
             window.alert("Motyw nie może się kończyć w tym miejscu.");
             return false;
         }
             point.setStart(container, offset);
             return point;
         }
-        
+
         var spoint = createPoint(range.startContainer, range.startOffset);
         var epoint = createPoint(range.endContainer, range.endOffset);
-               
+
         var mtag, btag, etag, errors;
 
         // insert theme-ref
                                 spoint.insertNode(btag[0])
                                 btag.replaceWith(text);
                                 selection.removeAllRanges();
-                                openForEdit($('.motyw[theme-class=' + id + ']'));
+                                openForEdit($('[x-node="motyw"][theme-class="' + id + '"]'));
                             }
                         });
                     }
         });
     }
 
-    function addSymbol() {
-        if($('div.html-editarea textarea')[0]) {
+    function addSymbol(caret) {
+        let editArea;
+
+        if (caret) {
+            editArea = $("textarea", caret.element)[0];
+        } else {
+            editArea = $('div.html-editarea textarea')[0];
+        }
+
+        if(editArea) {
             var specialCharsContainer = $("<div id='specialCharsContainer'><a href='#' id='specialCharsClose'>Zamknij</a><table id='tableSpecialChars' style='width: 600px;'></table></div>");
-                        
+
             var specialChars = [' ', 'Ą','ą','Ć','ć','Ę','ę','Ł','ł','Ń','ń','Ó','ó','Ś','ś','Ż','ż','Ź','ź','Á','á','À','à',
             'Â','â','Ä','ä','Å','å','Ā','ā','Ă','ă','Ã','ã',
             'Æ','æ','Ç','ç','Č','č','Ċ','ċ','Ď','ď','É','é','È','è',
             '„','”','„”','«','»','«»','»«','’','[',']','~','|','−','·',
             '×','÷','≈','≠','±','≤','≥','∈'];
             var tableContent = "<tr>";
-            
+
             for(var i in specialChars) {
                 if(i % 14 == 0 && i > 0) {
                     tableContent += "</tr><tr>";
-                }              
-                tableContent += "<td><input type='button' class='specialBtn' value='"+specialChars[i]+"'/></td>";              
+                }
+                tableContent += "<td><input type='button' class='specialBtn' value='"+specialChars[i]+"'/></td>";
             }
-            
-            tableContent += "</tr>";                                   
-            $("#content").append(specialCharsContainer);
-            
-            
+
+            tableContent += "</tr>";
+            $("body").append(specialCharsContainer);
+
+
              // localStorage for recently used characters - reading
              if (typeof(localStorage) != 'undefined') {
                  if (localStorage.getItem("recentSymbols")) {
                      var recentArray = recent.split(";");
                      var recentRow = "";
                      for(var i in recentArray.reverse()) {
-                        recentRow += "<td><input type='button' class='specialBtn recentSymbol' value='"+recentArray[i]+"'/></td>";              
+                        recentRow += "<td><input type='button' class='specialBtn recentSymbol' value='"+recentArray[i]+"'/></td>";
                      }
-                     recentRow = "<tr>" + recentRow + "</tr>";                              
+                     recentRow = "<tr>" + recentRow + "</tr>";
                  }
-             }            
+             }
             $("#tableSpecialChars").append(recentRow);
             $("#tableSpecialChars").append(tableContent);
-            
+
             /* events */
-            
+
             $('.specialBtn').click(function(){
-                var editArea = $('div.html-editarea textarea')[0];
                 var insertVal = $(this).val();
-                
+
                 // if we want to surround text with quotes
                 // not sure if just check if value has length == 2
-                
-                if (insertVal.length == 2) {
-                    var startTag = insertVal[0];
-                    var endTag = insertVal[1];
-                               var textAreaOpened = editArea;                                                  
-                               //IE support
-                               if (document.selection) {
-                                   textAreaOpened.focus();
-                                   sel = document.selection.createRange();
-                                   sel.text = startTag + sel.text + endTag;
-                               }
-                               //MOZILLA/NETSCAPE support
-                               else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') {
-                                   var startPos = textAreaOpened.selectionStart;
-                                   var endPos = textAreaOpened.selectionEnd;
-                                   textAreaOpened.value = textAreaOpened.value.substring(0, startPos)
-                                         + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length);
-                               }                
+
+                if (caret) {
+                    caret.insertChar(insertVal);
+                    caret.focus();
                 } else {
-                    // if we just want to insert single symbol
-                    insertAtCaret(editArea, insertVal);
+                    if (insertVal.length == 2) {
+                        var startTag = insertVal[0];
+                        var endTag = insertVal[1];
+                       var textAreaOpened = editArea;
+                       //IE support
+                       if (document.selection) {
+                           textAreaOpened.focus();
+                           sel = document.selection.createRange();
+                           sel.text = startTag + sel.text + endTag;
+                       }
+                       //MOZILLA/NETSCAPE support
+                       else if (textAreaOpened.selectionStart || textAreaOpened.selectionStart == '0') {
+                           var startPos = textAreaOpened.selectionStart;
+                           var endPos = textAreaOpened.selectionEnd;
+                           textAreaOpened.value = textAreaOpened.value.substring(0, startPos)
+                               + startTag + textAreaOpened.value.substring(startPos, endPos) + endTag + textAreaOpened.value.substring(endPos, textAreaOpened.value.length);
+                       }
+                    } else {
+                        insertAtCaret(editArea, insertVal);
+                    }
                 }
-                
+
                 // localStorage for recently used characters - saving
                 if (typeof(localStorage) != 'undefined') {
                     if (localStorage.getItem("recentSymbols")) {
                     }
                 }
                 $(specialCharsContainer).remove();
-            });         
+            });
             $('#specialCharsClose').click(function(){
                 $(specialCharsContainer).remove();
-            });                   
-            
+            });
+
         } else {
             window.alert('Najedź na fragment tekstu, wybierz "Edytuj" i ustaw kursor na miejscu gdzie chcesz wstawić symbol.');
         }
     }
 
-    function insertAtCaret(txtarea,text) { 
+    function insertAtCaret(txtarea,text) {
         /* http://www.scottklarr.com/topic/425/how-to-insert-text-into-a-textarea-where-the-cursor-is/ */
-        var scrollPos = txtarea.scrollTop; 
-        var strPos = 0; 
+        var scrollPos = txtarea.scrollTop;
+        var strPos = 0;
         var backStart = 0;
         var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? "ff" : (document.selection ? "ie" : false ) );
-        if (br == "ie") { 
+        if (br == "ie") {
             txtarea.focus();
-            var range = document.selection.createRange(); 
-            range.moveStart ('character', -txtarea.value.length); 
-            strPos = backStart = range.text.length; 
+            var range = document.selection.createRange();
+            range.moveStart ('character', -txtarea.value.length);
+            strPos = backStart = range.text.length;
         } else if (br == "ff") {
-            strPos = txtarea.selectionStart; 
+            strPos = txtarea.selectionStart;
             backStart = txtarea.selectionEnd;
         }
-        var front = (txtarea.value).substring(0,strPos); 
-        var back = (txtarea.value).substring(backStart,txtarea.value.length); 
-        txtarea.value=front+text+back; 
-        strPos = strPos + text.length; 
-        if (br == "ie") { 
-            txtarea.focus(); 
-            var range = document.selection.createRange(); 
-            range.moveStart ('character', -txtarea.value.length); 
-            range.moveStart ('character', strPos); 
-            range.moveEnd ('character', 0); 
-            range.select(); 
-        } else if (br == "ff") { 
-            txtarea.selectionStart = strPos; 
-            txtarea.selectionEnd = strPos; 
-            txtarea.focus(); 
-        } 
-        txtarea.scrollTop = scrollPos; 
-    } 
+        var front = (txtarea.value).substring(0,strPos);
+        var back = (txtarea.value).substring(backStart,txtarea.value.length);
+        txtarea.value=front+text+back;
+        strPos = strPos + text.length;
+        if (br == "ie") {
+            txtarea.focus();
+            var range = document.selection.createRange();
+            range.moveStart ('character', -txtarea.value.length);
+            range.moveStart ('character', strPos);
+            range.moveEnd ('character', 0);
+            range.select();
+        } else if (br == "ff") {
+            txtarea.selectionStart = strPos;
+            txtarea.selectionEnd = strPos;
+            txtarea.focus();
+        }
+        txtarea.scrollTop = scrollPos;
+    }
 
     /* open edition window for selected fragment */
     function openForEdit($origin){
             $box = $origin;
         }
         var x = $box[0].offsetLeft;
-        var y = $box[0].offsetTop;        
-        
+        var y = $box[0].offsetTop;
+
         var w = $box.outerWidth();
         var h = $box.innerHeight();
 
             w = Math.max(w, 400);
             h = Math.max(h, 60);
             if($('.htmlview div').offset().left + $('.htmlview div').width() > ($('.vsplitbar').offset().left - 480)){
-                x = -(Math.max($origin.offset().left, $origin.width())); 
+                x = -(Math.max($origin.offset().left, $origin.width()));
             } else {
                 x = 100;
             }
         }
+        if ($origin.is('.reference-inline-box')) {
+            w = 400;
+            h = 32;
+            y -= 32;
+            x = Math.min(
+                x,
+                $('.htmlview div').offset().left + $('.htmlview div').width() - 400
+            );
+        }
 
         // start edition on this node
         var $overlay = $('<div class="html-editarea"><button class="accept-button">Zapisz</button><button class="delete-button">Usuń</button><button class="tytul-button akap-edit-button">tytuł dzieła</button><button class="wyroznienie-button akap-edit-button">wyróżnienie</button><button class="slowo-button akap-edit-button">słowo obce</button><button class="znak-button akap-edit-button">znak spec.</button><textarea></textarea></div>').css({
             top: y,
             width: w
         }).appendTo($box[0].offsetParent || $box.parent()).show();
-        
 
-        if ($origin.is('.motyw')) {
+
+        if ($origin.is('*[x-edit-no-format]')) {
            $('.akap-edit-button').remove();
-            withThemes(function(canonThemes){
-                $('textarea', $overlay).autocomplete(canonThemes, {
-                    autoFill: true,
-                    multiple: true,
-                    selectFirst: true,
-                    highlight: false
-                });
-            })
         }
 
-        if ($origin.is('.motyw')){
+        if ($origin.is('[x-node="motyw"]')) {
+            $.themes.autocomplete($('textarea', $overlay));
+        }
+
+        if ($origin.is('[x-node="motyw"]')){
             $('.delete-button', $overlay).click(function(){
-                if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten motyw ?")) {
-                    $('[theme-class=' + $origin.attr('theme-class') + ']').remove();
+                if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten motyw?")) {
+                    $('[theme-class="' + $origin.attr('theme-class') + '"]').remove();
                     $overlay.remove();
                     $(document).unbind('click.blur-overlay');
                     return false;
                 };
             });
         }
-        else if($box.is('*[x-annotation-box]')) {
+        else if($box.is('*[x-annotation-box]') || $origin.is('*[x-edit-attribute]') || $origin.is('*[x-node="uwaga"]')) {
+            let q;
+            switch ($origin.attr('x-node')) {
+            case 'uwaga':
+                q = 'tę uwagę';
+                break;
+            case 'ref':
+                q = 'tę referencję';
+                break
+            default:
+                q = 'ten przypis';
+            }
             $('.delete-button', $overlay).click(function(){
-                if (window.confirm("Czy jesteś pewien, że chcesz usunąć ten przypis?")) {
+                if (window.confirm("Czy jesteś pewien, że chcesz usunąć " + q + "?")) {
                     $origin.remove();
                     $overlay.remove();
                     $(document).unbind('click.blur-overlay');
 
         var serializer = new XMLSerializer();
 
+        if($box.attr("x-edit-attribute")) {
+            source = $('<span x-pass-thru="true"/>');
+            source.text($box.attr("x-a-wl-" + $box.attr("x-edit-attribute")));
+            source = source[0];
+        } else {
+            source = $box[0];
+        }
+
         html2text({
-            element: $box[0],
+            element: source,
             stripOuter: true,
             success: function(text){
                 $('textarea', $overlay).val($.trim(text));
                     var nodeName = $box.attr('x-node') || 'pe';
                     var insertedText = $('textarea', $overlay).val();
 
-                    if ($origin.is('.motyw')) {
+                    if ($origin.is('[x-node="motyw"]')) {
                         insertedText = insertedText.replace(/,\s*$/, '');
                     }
 
+                    if($box.attr("x-edit-attribute")) {
+                        xml = '<' + nodeName + ' ' + $box.attr("x-edit-attribute") + '="' + insertedText + '"/>';
+                    } else {
+                        xml = '<' + nodeName + '>' + insertedText + '</' + nodeName + '>';
+                    }
+
+
                     xml2html({
-                        xml: '<' + nodeName + '>' + insertedText + '</' + nodeName + '>',
+                        xml: xml,
                         success: function(element){
                             if (nodeName == 'out-of-flow-text') {
                                 $(element).children().insertAfter($origin);
                                 $origin.remove()
                             }
+                            else if ($box.attr('x-edit-attribute')) {
+                                $(element).insertAfter($origin);
+                                $origin.remove();
+                            }
                             else {
                                 $origin.html($(element).html());
                             }
                             alert('Błąd! ' + text);
                         }
                     })
-                    
+
                     var msg = $("<div class='saveNotify'><p>Pamiętaj, żeby zapisać swoje zmiany.</p></div>");
                     $("#base").prepend(msg);
                     $('#base .saveNotify').fadeOut(3000, function(){
-                        $(this).remove(); 
+                        $(this).remove();
                     });
                 }
 
                            addSymbol();
                            return false;
                        }
-                       
-                       var myField = textAreaOpened;                   
-                        
+
+                       var myField = textAreaOpened;
+
                        //IE support
                        if (document.selection) {
                            textAreaOpened.focus();
         });
     }
 
+    function createUwagaBefore(before) {
+        xml2html({
+            xml: '<uwaga/>',
+            success: function(element){
+                let $element = $(element);
+                $element.insertBefore(before);
+                openForEdit($element);
+            }
+        });
+    }
+
     function VisualPerspective(options){
+        perspective = self = this;
 
         var old_callback = options.callback;
 
         options.callback = function(){
             var element = $("#html-view");
-            var button = $('<button class="edit-button">Edytuj</button>');
+            var button = $('<button class="edit-button active-block-button">Edytuj</button>');
+            var uwagaButton = $('<button class="uwaga-button active-block-button">Uwaga</button>');
 
             if (!CurrentDocument.readonly) {
+
                 $('#html-view').bind('mousemove', function(event){
                     var editable = $(event.target).closest('*[x-editable]');
-                    $('.active', element).not(editable).removeClass('active').children('.edit-button').remove();
+                    $('.active', element).not(editable).removeClass('active').children('.active-block-button').remove();
 
                     if (!editable.hasClass('active')) {
                         editable.addClass('active').append(button);
+                        if (!editable.is('[x-edit-attribute]') &&
+                            !editable.is('.annotation-inline-box') &&
+                            !editable.is('[x-edit-no-format]')
+                           ) {
+                            editable.append(uwagaButton);
+                        }
                     }
                     if (editable.is('.annotation-inline-box')) {
                         $('*[x-annotation-box]', editable).css({
-                            position: 'absolute',
-                            left: event.clientX - editable.offset().left + 5,
-                            top: event.clientY - editable.offset().top + 5
                         }).show();
                     }
-                    else {
-                        $('*[x-annotation-box]').hide();
-                    }
+                });
+
+                perspective.caret = new Caret(element);
+                
+                $('#insert-reference-button').click(function(){
+                    self.addReference();
+                    return false;
                 });
 
                 $('#insert-annotation-button').click(function(){
                 $('#insert-theme-button').click(function(){
                     addTheme();
                     return false;
-                });            
+                });
+
+
+                $(".insert-inline-tag").click(function() {
+                    perspective.insertInlineTag($(this).attr('data-tag'));
+                    return false;
+                });
+
+                $(".insert-char").click(function() {
+                    addSymbol(caret=perspective.caret);
+                    return false;
+                });
 
-                $('.edit-button').live('click', function(event){
+                $(document).on('click', '.edit-button', function(event){
                     event.preventDefault();
                     openForEdit($(this).parent());
                 });
 
+                $(document).on('click', '.uwaga-button', function(event){
+                    event.preventDefault();
+                    createUwagaBefore($(this).parent());
+                });
             }
 
-            $('.motyw').live('click', function(){
+            $(document).on('click', '[x-node="motyw"]', function(){
                 selectTheme($(this).attr('theme-class'));
             });
 
+            element.on('click', '.annotation', function(event) {
+                event.preventDefault();
+                event.redakcja_caret_ignore = true;
+                $('[x-annotation-box]', $(this).parent()).toggleClass('editing');
+                perspective.caret.detach();
+            });
+
             old_callback.call(this);
         };
 
 
     VisualPerspective.prototype = new $.wiki.Perspective();
 
-    VisualPerspective.prototype.freezeState = function(){
-
-    };
-
     VisualPerspective.prototype.onEnter = function(success, failure){
         $.wiki.Perspective.prototype.onEnter.call(this);
 
                 callback();
         }
 
+        perspective = this;
         xml2html({
             xml: this.doc.text,
+            base: this.doc.getBase(),
             success: function(element){
+
                 var htmlView = $('#html-view');
                 htmlView.html(element);
-                htmlView.find('*[x-node]').dblclick(function(e) {
-                    if($(e.target).is('textarea'))
-                        return;
-                    var selection = window.getSelection();
-                    selection.collapseToStart();
-                    selection.modify('extend', 'forward', 'word');
-                    e.stopPropagation();
-                });
+
                 _finalize(success);
             },
             error: function(text, source){
     VisualPerspective.prototype.onExit = function(success, failure){
         var self = this;
 
+        self.caret.detach();
+
+        $.wiki.exitTab('#PropertiesPerspective');
+        
         $.blockUI({
             message: 'Zapisywanie widoku...'
         });
         });
     };
 
+    VisualPerspective.prototype.insertInlineTag = function(tag) {
+        this.caret.detach();
+
+        let selection = window.getSelection();
+        var n = selection.rangeCount;
+        if (n != 1 || selection.isCollapsed) {
+            window.alert("Nie zaznaczono obszaru");
+            return false
+        }
+        let range = selection.getRangeAt(0);
+
+        // Make sure that:
+        // Both ends are in the same x-node container.
+        // TODO: That the container is a inline-text container.
+        let node = range.startContainer;
+        if (node.nodeType == node.TEXT_NODE) {
+            node = node.parentNode;
+        }
+        let endNode = range.endContainer;
+        if (endNode.nodeType == endNode.TEXT_NODE) {
+            endNode = endNode.parentNode;
+        }
+        if (node != endNode) {
+            window.alert("Zły obszar.");
+            return false;
+        }
+
+        // We will construct a HTML element with the range selected.
+        let div = $("<span x-pass-thru='true'>");
+
+        contents = $(node).contents();
+        let startChildIndex = node == range.startContainer ? 0 : contents.index(range.startContainer);
+        let endChildIndex = contents.index(range.endContainer);
+
+        current = range.startContainer;
+        if (current.nodeType == current.TEXT_NODE) {
+            current = current.splitText(range.startOffset);
+        }
+        while (current != range.endContainer) {
+            n = current.nextSibling;
+            $(current).appendTo(div);
+            current = n;
+        }
+        if (current.nodeType == current.TEXT_NODE) {
+            end = current.splitText(range.endOffset);
+        }
+        $(current).appendTo(div);
+        
+        html2text({
+            element: div[0],
+            success: function(d) {
+                xml2html({
+                    xml: d = '<' + tag + '>' + d + '</' + tag + '>',
+                    success: function(html) {
+                        // What if no end?
+                        node.insertBefore($(html)[0], end);
+                    }
+                });
+            },
+            error: function(a, b) {
+                console.log(a, b);
+            }
+        });
+    };
+
+    VisualPerspective.prototype.insertAtRange = function(range, elem) {
+        let self = this;
+        let $end = $(range.endContainer);
+        if ($end.attr('id') == 'caret') {
+            self.caret.insert(elem);
+        } else {
+            range.insertNode(elem[0]);
+        }
+    }
+
+    VisualPerspective.prototype.addReference = function() {
+        let self = this;
+        var selection = window.getSelection();
+        var n = selection.rangeCount;
+
+        // TODO: if no selection, take caret position..
+        if (n == 0) {
+            window.alert("Nie zaznaczono żadnego obszaru");
+            return false;
+        }
+
+        var range = selection.getRangeAt(n - 1);
+        if (!verifyTagInsertPoint(range.endContainer)) {
+            window.alert("Nie można wstawić w to miejsce referencji.");
+            return false;
+        }
+
+        var tag = $('<span></span>');
+
+        range.collapse(false);
+        self.insertAtRange(range, tag);
+
+        xml2html({
+            xml: '<ref href=""/>',
+            success: function(text){
+                var t = $(text);
+                tag.replaceWith(t);
+                openForEdit(t);
+            },
+            error: function(){
+                tag.remove();
+                alert('Błąd przy dodawaniu referncji:' + errors);
+            }
+        })
+    }
+
     $.wiki.VisualPerspective = VisualPerspective;
 
 })(jQuery);